Compare commits

...

2 Commits

Author SHA1 Message Date
d32e367383 Добавлен архитектурный скетч 2025-12-13 11:19:11 +03:00
749c2b4e95 проблемы 2025-11-26 09:25:07 +03:00
7 changed files with 2062 additions and 4 deletions

635
C4-Architecture.md Normal file
View File

@ -0,0 +1,635 @@
[Назад](/README.md)
# C4 Architecture Diagrams - TaskManager
## Содержание
1. [Level 1: System Context](#level-1-system-context)
2. [Level 2: Container Diagram](#level-2-container-diagram)
3. [Level 3: Component Diagram - Tasks Service](#level-3-component-diagram---tasks-service)
4. [Level 3: Component Diagram - Adapter Layer](#level-3-component-diagram---adapter-layer)
---
## Level 1: System Context
Показывает TaskManager в контексте пользователей и внешних систем.
```mermaid
C4Context
title System Context diagram for TaskManager
Person(hotel_staff, "Hotel Staff", "Сотрудники отеля (горничные, техники, менеджеры)")
Person(admin, "System Admin", "Администратор системы")
Person(guest, "Hotel Guest", "Гость отеля")
System(taskmanager, "TaskManager", "Платформа для управления задачами между подразделениями отеля и интеграции с внешними системами")
System_Ext(pms, "PMS System", "Система управления отелем (Opera, Fidelio)")
System_Ext(erp, "ERP System", "Система управления ресурсами")
System_Ext(housekeeping, "Housekeeping App", "Приложение для управления уборкой")
System_Ext(email, "Email System", "SMTP сервер для отправки email")
System_Ext(sms, "SMS Gateway", "Сервис отправки SMS (Twilio)")
System_Ext(telegram, "Telegram", "Telegram Bot API")
System_Ext(s3, "AWS S3", "Хранилище файлов")
Rel(hotel_staff, taskmanager, "Создает и управляет задачами", "Web/Mobile")
Rel(admin, taskmanager, "Настраивает систему, связи, роли", "Web Admin")
Rel(guest, taskmanager, "Создает запросы на обслуживание", "Telegram Bot")
Rel(taskmanager, pms, "Получает/отправляет данные о бронированиях, номерах", "REST API/Webhook")
Rel(taskmanager, erp, "Интегрируется с учетом ресурсов", "REST API")
Rel(taskmanager, housekeeping, "Отправляет задачи на уборку", "REST API/Push")
Rel(taskmanager, email, "Отправляет уведомления", "SMTP")
Rel(taskmanager, sms, "Отправляет SMS уведомления", "REST API")
Rel(taskmanager, telegram, "Получает запросы гостей, отправляет уведомления", "Webhook/Bot API")
Rel(taskmanager, s3, "Хранит файлы и фото", "S3 API")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="2")
```
---
## Level 2: Container Diagram
Показывает основные контейнеры (приложения и хранилища данных) внутри TaskManager.
```mermaid
C4Container
title Container diagram for TaskManager
Person(hotel_staff, "Hotel Staff", "Сотрудники отеля")
Person(admin, "System Admin", "Администратор системы")
Person(guest, "Hotel Guest", "Гость отеля")
System_Ext(pms, "PMS System", "Opera/Fidelio")
System_Ext(erp, "ERP System", "ERP")
System_Ext(housekeeping_ext, "Housekeeping App", "External App")
System_Ext(email_ext, "Email System", "SMTP")
System_Ext(sms_ext, "SMS Gateway", "Twilio")
System_Ext(telegram_ext, "Telegram", "Bot API")
System_Ext(s3_ext, "AWS S3", "File Storage")
Container_Boundary(taskmanager, "TaskManager System") {
Container(web_admin, "Web Admin", "React, TypeScript", "Веб-приложение для настройки системы и управления")
Container(mobile_app, "Mobile App", "React Native/Flutter", "Мобильное приложение для сотрудников")
Container(api_gateway, "API Gateway", "Kong/Envoy", "Единая точка входа, маршрутизация, аутентификация")
Container(tasks_service, "Tasks Service", "Python, FastAPI, gRPC", "Управление задачами")
Container(connections_service, "Connections Service", "Python, FastAPI, gRPC", "Управление связями между адаптерами")
Container(users_service, "Users Service", "Python, FastAPI, gRPC", "Управление пользователями")
Container(permissions_service, "Permissions Service", "Python, FastAPI, gRPC", "Управление ролями и правами (RBAC)")
Container(notification_service, "Notification Service", "Python, FastAPI", "Отправка уведомлений через разные каналы")
Container(file_storage_service, "File Storage Service", "Python, FastAPI", "Управление файлами")
Container(audit_service, "Audit Service", "Python, FastAPI", "Логирование всех действий")
Container(scheduler_service, "Scheduler Service", "Python, FastAPI", "Управление периодическими задачами")
Container(events_service, "Events Service", "Python, FastAPI, gRPC", "Управление мероприятиями")
Container(pms_adapter, "PMS Adapter", "Python", "Адаптер для PMS системы")
Container(erp_adapter, "ERP Adapter", "Python", "Адаптер для ERP системы")
Container(housekeeping_adapter, "Housekeeping Adapter", "Python", "Адаптер для приложения уборки")
Container(telegram_adapter, "Telegram Bot Adapter", "Python", "Адаптер для Telegram бота")
ContainerQueue(kafka, "Message Broker", "Apache Kafka", "Асинхронная коммуникация между сервисами")
ContainerDb(postgres, "Database", "PostgreSQL", "Хранение данных системы")
ContainerDb(redis, "Cache", "Redis", "Кэширование данных, сессии")
}
Rel(hotel_staff, web_admin, "Использует", "HTTPS")
Rel(hotel_staff, mobile_app, "Использует", "HTTPS")
Rel(admin, web_admin, "Настраивает систему", "HTTPS")
Rel(guest, telegram_adapter, "Отправляет запросы", "Telegram")
Rel(web_admin, api_gateway, "Делает API запросы", "REST/gRPC-Web")
Rel(mobile_app, api_gateway, "Делает API запросы", "REST/gRPC")
Rel(api_gateway, tasks_service, "Маршрутизирует запросы", "gRPC")
Rel(api_gateway, users_service, "Маршрутизирует запросы", "gRPC")
Rel(api_gateway, connections_service, "Маршрутизирует запросы", "gRPC")
Rel(api_gateway, events_service, "Маршрутизирует запросы", "gRPC")
Rel(api_gateway, file_storage_service, "Маршрутизирует запросы", "REST")
Rel(tasks_service, kafka, "Публикует события", "Kafka Protocol")
Rel(connections_service, kafka, "Публикует/читает события", "Kafka Protocol")
Rel(scheduler_service, kafka, "Публикует триггеры", "Kafka Protocol")
Rel(events_service, kafka, "Публикует события", "Kafka Protocol")
Rel(notification_service, kafka, "Читает события", "Kafka Protocol")
Rel(audit_service, kafka, "Читает все события", "Kafka Protocol")
Rel(tasks_service, permissions_service, "Проверяет права", "gRPC")
Rel(users_service, permissions_service, "Проверяет права", "gRPC")
Rel(pms_adapter, kafka, "Публикует сообщения", "Kafka Protocol")
Rel(erp_adapter, kafka, "Публикует сообщения", "Kafka Protocol")
Rel(housekeeping_adapter, kafka, "Публикует сообщения", "Kafka Protocol")
Rel(telegram_adapter, kafka, "Публикует сообщения", "Kafka Protocol")
Rel(pms_adapter, pms, "Получает/отправляет данные", "REST API/Webhook")
Rel(erp_adapter, erp, "Получает/отправляет данные", "REST API")
Rel(housekeeping_adapter, housekeeping_ext, "Отправляет задачи", "REST API/Push")
Rel(telegram_adapter, telegram_ext, "Взаимодействует с ботом", "Webhook/Bot API")
Rel(notification_service, email_ext, "Отправляет email", "SMTP")
Rel(notification_service, sms_ext, "Отправляет SMS", "REST API")
Rel(notification_service, telegram_ext, "Отправляет сообщения", "Bot API")
Rel(file_storage_service, s3_ext, "Хранит файлы", "S3 API")
Rel(tasks_service, postgres, "Читает/пишет данные", "SQL")
Rel(users_service, postgres, "Читает/пишет данные", "SQL")
Rel(connections_service, postgres, "Читает/пишет данные", "SQL")
Rel(permissions_service, postgres, "Читает/пишет данные", "SQL")
Rel(scheduler_service, postgres, "Читает/пишет данные", "SQL")
Rel(events_service, postgres, "Читает/пишет данные", "SQL")
Rel(audit_service, postgres, "Пишет логи", "SQL")
Rel(file_storage_service, postgres, "Пишет метаданные", "SQL")
Rel(tasks_service, redis, "Кэширует данные", "Redis Protocol")
Rel(users_service, redis, "Кэширует данные", "Redis Protocol")
Rel(permissions_service, redis, "Кэширует права", "Redis Protocol")
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="2")
```
---
## Level 3: Component Diagram - Tasks Service
Показывает внутреннюю структуру Tasks Service.
```mermaid
C4Component
title Component diagram for Tasks Service
Container_Ext(api_gateway, "API Gateway", "Kong/Envoy", "Точка входа")
Container_Ext(kafka, "Kafka", "Apache Kafka", "Message Broker")
ContainerDb_Ext(postgres, "PostgreSQL", "Database", "Основная БД")
ContainerDb_Ext(redis, "Redis", "Cache", "Кэш")
Container_Ext(permissions_service, "Permissions Service", "Python, gRPC", "Проверка прав")
Container_Ext(file_storage_service, "File Storage Service", "Python", "Управление файлами")
Container_Boundary(tasks_service, "Tasks Service") {
Component(grpc_api, "gRPC API", "Python, gRPC", "Обработка gRPC запросов")
Component(rest_api, "REST API", "FastAPI", "Обработка REST запросов (fallback)")
Component(task_controller, "Task Controller", "Python", "Обработка бизнес-логики задач")
Component(status_controller, "Status Controller", "Python", "Управление статусами задач")
Component(dependency_controller, "Dependency Controller", "Python", "Управление зависимостями")
Component(history_controller, "History Controller", "Python", "Управление историей изменений")
Component(task_repository, "Task Repository", "SQLAlchemy", "Работа с БД задач")
Component(status_repository, "Status Repository", "SQLAlchemy", "Работа с БД статусов")
Component(dependency_repository, "Dependency Repository", "SQLAlchemy", "Работа с БД зависимостей")
Component(history_repository, "History Repository", "SQLAlchemy", "Работа с БД истории")
Component(kafka_producer, "Kafka Producer", "aiokafka", "Публикация событий в Kafka")
Component(kafka_consumer, "Kafka Consumer", "aiokafka", "Чтение событий из Kafka")
Component(cache_manager, "Cache Manager", "Redis Client", "Управление кэшем")
Component(permission_client, "Permission Client", "gRPC Client", "Проверка прав доступа")
Component(task_validator, "Task Validator", "Pydantic", "Валидация данных задач")
Component(event_mapper, "Event Mapper", "Python", "Маппинг событий")
}
Rel(api_gateway, grpc_api, "Отправляет gRPC запросы", "gRPC")
Rel(api_gateway, rest_api, "Отправляет REST запросы", "HTTP/JSON")
Rel(grpc_api, task_controller, "Вызывает методы")
Rel(rest_api, task_controller, "Вызывает методы")
Rel(task_controller, task_validator, "Валидирует данные")
Rel(task_controller, permission_client, "Проверяет права")
Rel(task_controller, task_repository, "Работает с задачами")
Rel(task_controller, status_controller, "Изменяет статусы")
Rel(task_controller, dependency_controller, "Управляет зависимостями")
Rel(task_controller, history_controller, "Записывает историю")
Rel(task_controller, cache_manager, "Кэширует данные")
Rel(task_controller, kafka_producer, "Публикует события")
Rel(status_controller, status_repository, "Работает со статусами")
Rel(dependency_controller, dependency_repository, "Работает с зависимостями")
Rel(history_controller, history_repository, "Работает с историей")
Rel(kafka_consumer, event_mapper, "Маппит события")
Rel(event_mapper, task_controller, "Обрабатывает события")
Rel(task_repository, postgres, "Выполняет SQL запросы", "SQL")
Rel(status_repository, postgres, "Выполняет SQL запросы", "SQL")
Rel(dependency_repository, postgres, "Выполняет SQL запросы", "SQL")
Rel(history_repository, postgres, "Выполняет SQL запросы", "SQL")
Rel(cache_manager, redis, "Кэширует/читает данные", "Redis Protocol")
Rel(permission_client, permissions_service, "Проверяет права", "gRPC")
Rel(kafka_producer, kafka, "Публикует события", "Kafka Protocol")
Rel(kafka_consumer, kafka, "Читает события", "Kafka Protocol")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```
---
## Level 3: Component Diagram - Adapter Layer
Показывает внутреннюю структуру адаптера (на примере PMS Adapter).
```mermaid
C4Component
title Component diagram for PMS Adapter (Example)
System_Ext(pms_system, "PMS System", "Opera/Fidelio", "Внешняя PMS система")
Container_Ext(kafka, "Kafka", "Apache Kafka", "Message Broker")
Container_Ext(postgres, "PostgreSQL", "Database", "Хранение состояния адаптера")
Container_Boundary(pms_adapter, "PMS Adapter") {
Component(webhook_handler, "Webhook Handler", "FastAPI", "Принимает webhook от PMS")
Component(api_poller, "API Poller", "Python, APScheduler", "Опрашивает PMS API по расписанию")
Component(rest_client, "REST Client", "httpx", "HTTP клиент для PMS API")
Component(inbound_transformer, "Inbound Transformer", "Python", "PMS формат → Стандартный формат")
Component(outbound_transformer, "Outbound Transformer", "Python", "Стандартный формат → PMS формат")
Component(message_validator, "Message Validator", "Pydantic", "Валидация сообщений")
Component(event_publisher, "Event Publisher", "aiokafka", "Публикация событий в Kafka")
Component(event_consumer, "Event Consumer", "aiokafka", "Чтение событий из Kafka")
Component(state_manager, "State Manager", "SQLAlchemy", "Управление состоянием синхронизации")
Component(error_handler, "Error Handler", "Python", "Обработка ошибок и retry")
Component(config_manager, "Config Manager", "Python", "Управление конфигурацией")
}
Rel(pms_system, webhook_handler, "Отправляет webhook", "HTTP/JSON")
Rel(api_poller, rest_client, "Запрашивает данные")
Rel(rest_client, pms_system, "Делает API запросы", "REST/SOAP")
Rel(webhook_handler, inbound_transformer, "Передает данные")
Rel(api_poller, inbound_transformer, "Передает данные")
Rel(inbound_transformer, message_validator, "Валидирует сообщение")
Rel(message_validator, event_publisher, "Публикует валидное событие")
Rel(event_consumer, kafka, "Читает исходящие события", "Kafka Protocol")
Rel(event_consumer, outbound_transformer, "Передает событие")
Rel(outbound_transformer, rest_client, "Отправляет в PMS")
Rel(event_publisher, kafka, "Публикует входящие события", "Kafka Protocol")
Rel(state_manager, postgres, "Сохраняет состояние", "SQL")
Rel(error_handler, state_manager, "Логирует ошибки")
Rel(webhook_handler, error_handler, "Обрабатывает ошибки")
Rel(api_poller, error_handler, "Обрабатывает ошибки")
Rel(rest_client, error_handler, "Обрабатывает ошибки")
Rel(config_manager, api_poller, "Предоставляет конфигурацию")
Rel(config_manager, rest_client, "Предоставляет конфигурацию")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```
---
## Deployment Diagram (Kubernetes)
Показывает развертывание в Kubernetes кластере.
```mermaid
C4Deployment
title Deployment Diagram for TaskManager (Kubernetes)
Deployment_Node(k8s_cluster, "Kubernetes Cluster", "GKE/EKS/AKS") {
Deployment_Node(ingress_ns, "Namespace: ingress") {
Container(ingress, "Ingress Controller", "NGINX/Traefik", "Входная точка для внешнего трафика")
}
Deployment_Node(gateway_ns, "Namespace: gateway") {
Container(api_gateway, "API Gateway", "Kong/Envoy", "3 replicas", "Маршрутизация и аутентификация")
}
Deployment_Node(services_ns, "Namespace: services") {
Container(tasks_svc, "Tasks Service", "Python, FastAPI", "5 replicas", "Управление задачами")
Container(users_svc, "Users Service", "Python, FastAPI", "3 replicas", "Управление пользователями")
Container(connections_svc, "Connections Service", "Python, FastAPI", "2 replicas", "Управление связями")
Container(permissions_svc, "Permissions Service", "Python, FastAPI", "3 replicas", "RBAC")
Container(notification_svc, "Notification Service", "Python, FastAPI", "3 replicas", "Уведомления")
Container(file_storage_svc, "File Storage Service", "Python, FastAPI", "2 replicas", "Файлы")
Container(audit_svc, "Audit Service", "Python, FastAPI", "2 replicas", "Аудит")
Container(scheduler_svc, "Scheduler Service", "Python, FastAPI", "1 replica", "Планировщик")
Container(events_svc, "Events Service", "Python, FastAPI", "2 replicas", "Мероприятия")
}
Deployment_Node(adapters_ns, "Namespace: adapters") {
Container(pms_adapter, "PMS Adapter", "Python", "2 replicas", "PMS интеграция")
Container(erp_adapter, "ERP Adapter", "Python", "1 replica", "ERP интеграция")
Container(housekeeping_adapter, "Housekeeping Adapter", "Python", "2 replicas", "Уборка")
Container(telegram_adapter, "Telegram Adapter", "Python", "2 replicas", "Telegram бот")
}
Deployment_Node(data_ns, "Namespace: data") {
ContainerDb(postgres_primary, "PostgreSQL Primary", "PostgreSQL 15", "1 pod", "Основная БД (master)")
ContainerDb(postgres_replica, "PostgreSQL Replica", "PostgreSQL 15", "2 pods", "Реплики для чтения")
ContainerDb(redis_cluster, "Redis Cluster", "Redis 7", "3 pods", "Кэш и сессии")
ContainerQueue(kafka_cluster, "Kafka Cluster", "Apache Kafka", "3 brokers", "Message broker")
}
Deployment_Node(monitoring_ns, "Namespace: monitoring") {
Container(prometheus, "Prometheus", "Prometheus", "Сбор метрик")
Container(grafana, "Grafana", "Grafana", "Визуализация метрик")
Container(jaeger, "Jaeger", "Jaeger", "Distributed tracing")
}
}
Deployment_Node(external_services, "External Services") {
Container(s3, "AWS S3", "Object Storage", "Хранилище файлов")
Container(smtp, "SMTP Server", "Email", "Отправка email")
Container(sms_gateway, "SMS Gateway", "Twilio", "Отправка SMS")
}
Rel(ingress, api_gateway, "Routes traffic", "HTTPS")
Rel(api_gateway, tasks_svc, "Calls", "gRPC")
Rel(api_gateway, users_svc, "Calls", "gRPC")
Rel(api_gateway, connections_svc, "Calls", "gRPC")
Rel(api_gateway, events_svc, "Calls", "gRPC")
Rel(api_gateway, file_storage_svc, "Calls", "REST")
Rel(tasks_svc, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(connections_svc, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(scheduler_svc, kafka_cluster, "Publishes", "Kafka Protocol")
Rel(notification_svc, kafka_cluster, "Consumes", "Kafka Protocol")
Rel(audit_svc, kafka_cluster, "Consumes", "Kafka Protocol")
Rel(pms_adapter, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(erp_adapter, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(housekeeping_adapter, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(telegram_adapter, kafka_cluster, "Publishes/Consumes", "Kafka Protocol")
Rel(tasks_svc, postgres_primary, "Writes", "SQL")
Rel(tasks_svc, postgres_replica, "Reads", "SQL")
Rel(users_svc, postgres_primary, "Writes", "SQL")
Rel(users_svc, postgres_replica, "Reads", "SQL")
Rel(audit_svc, postgres_primary, "Writes logs", "SQL")
Rel(tasks_svc, redis_cluster, "Cache", "Redis Protocol")
Rel(users_svc, redis_cluster, "Cache", "Redis Protocol")
Rel(permissions_svc, redis_cluster, "Cache permissions", "Redis Protocol")
Rel(file_storage_svc, s3, "Stores files", "S3 API")
Rel(notification_svc, smtp, "Sends emails", "SMTP")
Rel(notification_svc, sms_gateway, "Sends SMS", "REST API")
Rel(prometheus, tasks_svc, "Scrapes metrics", "HTTP")
Rel(prometheus, users_svc, "Scrapes metrics", "HTTP")
Rel(grafana, prometheus, "Queries metrics", "HTTP")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
```
---
## Sequence Diagram: Creating Task from External System
Показывает последовательность действий при создании задачи из внешней системы.
```mermaid
sequenceDiagram
participant PMS as PMS System (Opera)
participant Adapter as PMS Adapter
participant Kafka as Apache Kafka
participant Connections as Connections Service
participant Tasks as Tasks Service
participant Permissions as Permissions Service
participant Audit as Audit Service
participant Notification as Notification Service
participant DB as PostgreSQL
participant Housekeeping as Housekeeping Adapter
participant HK_App as Housekeeping App
Note over PMS,HK_App: Сценарий: Гость выехал из номера, нужна уборка
PMS->>Adapter: Webhook: Guest Checkout (Room 305)
Adapter->>Adapter: Validate webhook signature
Adapter->>Adapter: Transform to standard format
Adapter->>Kafka: Publish: adapters.pms.checkout
Note over Kafka: Topic: adapters.pms.checkout
Kafka->>Connections: Consume: adapters.pms.checkout
Connections->>DB: Get routing rules for PMS → TaskManager
DB-->>Connections: Routing rules
Connections->>Connections: Apply rules: checkout → create cleaning task
Connections->>Kafka: Publish: connections.route_task
Note over Kafka: Topic: connections.route_task
Kafka->>Tasks: Consume: connections.route_task
Tasks->>Permissions: CheckPermission(source_adapter, create_task)
Permissions->>DB: Query permissions
DB-->>Permissions: Permission granted
Permissions-->>Tasks: Allowed
Tasks->>Tasks: Create task object
Tasks->>DB: INSERT INTO tasks (...)
DB-->>Tasks: Task created (id: uuid)
Tasks->>Kafka: Publish: tasks.created
Note over Kafka: Topic: tasks.created
par Parallel Processing
Kafka->>Audit: Consume: tasks.created
Audit->>DB: INSERT INTO audit_log
Kafka->>Notification: Consume: tasks.created
Notification->>DB: Get user notification preferences
DB-->>Notification: User prefers Telegram
Notification->>Notification: Send Telegram notification
Kafka->>Connections: Consume: tasks.created
Connections->>DB: Get routing rules for TaskManager → Housekeeping
DB-->>Connections: Route to Housekeeping Adapter
Connections->>Kafka: Publish: connections.route_task
end
Note over Kafka: Topic: connections.route_task
Kafka->>Housekeeping: Consume: connections.route_task
Housekeeping->>Housekeeping: Transform to Housekeeping App format
Housekeeping->>HK_App: POST /api/tasks (Room 305 cleaning)
HK_App-->>Housekeeping: Task assigned (assignee: Maria)
Housekeeping->>Kafka: Publish: adapters.housekeeping.task_assigned
Kafka->>Tasks: Consume: adapters.housekeeping.task_assigned
Tasks->>DB: UPDATE tasks SET assignee_id = ...
Tasks->>Kafka: Publish: tasks.assigned
Note over PMS,HK_App: Task created and assigned to housekeeping staff
```
---
## Sequence Diagram: Creating Event with Auto-Generated Tasks
Показывает создание мероприятия и автоматическую генерацию задач.
```mermaid
sequenceDiagram
participant User as Sales Manager
participant Web as Web Admin
participant Gateway as API Gateway
participant Events as Events Service
participant Tasks as Tasks Service
participant Kafka as Apache Kafka
participant DB as PostgreSQL
participant Notification as Notification Service
Note over User,Notification: Сценарий: Создание конференции на 50 человек
User->>Web: Create Event: "Marketing Conference"
Web->>Gateway: POST /api/v1/events (event details)
Gateway->>Gateway: Authenticate & Authorize
Gateway->>Events: CreateEvent(gRPC)
Events->>DB: INSERT INTO events
DB-->>Events: Event created (id: uuid)
Events->>Events: Generate tasks from event template
Note over Events: Tasks: Setup chairs, Prepare projector,<br/>Organize coffee break, etc.
loop For each generated task
Events->>Tasks: CreateTask(gRPC)
Tasks->>DB: INSERT INTO tasks
DB-->>Tasks: Task created
Tasks->>Kafka: Publish: tasks.created
Tasks-->>Events: Task ID
end
Events->>DB: INSERT INTO event_tasks (event_id, task_id)
Events->>Kafka: Publish: events.created
Events->>Kafka: Publish: events.tasks_generated
Events-->>Gateway: Event + generated tasks
Gateway-->>Web: 201 Created (event + tasks)
Web-->>User: Show created event with tasks
par Notify departments
Kafka->>Notification: Consume: tasks.created
loop For each task
Notification->>Notification: Get assignee notification prefs
Notification->>Notification: Send notification (Telegram/Email)
end
end
Note over User,Notification: All tasks created and departments notified
```
---
## Data Flow Diagram
Показывает потоки данных в системе.
```mermaid
flowchart TB
subgraph External["External Systems"]
PMS["PMS System"]
ERP["ERP System"]
Guest["Guest (Telegram)"]
end
subgraph Adapters["Adapter Layer"]
PMS_A["PMS Adapter"]
ERP_A["ERP Adapter"]
TG_A["Telegram Adapter"]
end
subgraph Kafka["Apache Kafka"]
T1["adapters.*"]
T2["tasks.*"]
T3["connections.*"]
T4["notifications.*"]
T5["audit.*"]
end
subgraph Core["Core Services"]
Connections["Connections Service<br/>(Routing Rules)"]
Tasks["Tasks Service<br/>(Task Management)"]
Users["Users Service"]
Permissions["Permissions Service"]
end
subgraph Support["Support Services"]
Notification["Notification Service"]
Audit["Audit Service"]
Scheduler["Scheduler Service"]
end
subgraph Data["Data Layer"]
DB["PostgreSQL"]
Cache["Redis"]
end
%% External to Adapters
PMS -->|"Webhook/API"| PMS_A
ERP -->|"API"| ERP_A
Guest -->|"Telegram Bot"| TG_A
%% Adapters to Kafka
PMS_A -->|"Publish events"| T1
ERP_A -->|"Publish events"| T1
TG_A -->|"Publish events"| T1
%% Kafka to Connections
T1 -->|"Consume"| Connections
%% Connections routing
Connections -->|"Route messages"| T3
T3 -->|"Consume"| Tasks
%% Tasks operations
Tasks -->|"Publish events"| T2
Tasks -->|"Query permissions"| Permissions
Tasks -->|"Write/Read"| DB
Tasks -->|"Cache"| Cache
%% Support services
T2 -->|"Consume"| Notification
T2 -->|"Consume"| Audit
Scheduler -->|"Trigger tasks"| T2
Notification -->|"Send notifications"| External
Audit -->|"Write logs"| DB
%% Users and Permissions
Users -->|"Write/Read"| DB
Permissions -->|"Write/Read"| DB
Permissions -->|"Cache permissions"| Cache
style Kafka fill:#ff9900
style Core fill:#00cc66
style Support fill:#3399ff
style Data fill:#cc66ff
```
---
## Notes
### Как использовать эти диаграммы:
1. **System Context (Level 1)**: Показывает TaskManager как черный ящик в контексте пользователей и внешних систем. Используйте для презентации бизнес-заказчикам.
2. **Container Diagram (Level 2)**: Показывает основные приложения и хранилища данных. Используйте для обсуждения с архитекторами и DevOps командой.
3. **Component Diagrams (Level 3)**: Показывают внутреннюю структуру отдельных сервисов. Используйте для разработчиков при проектировании конкретного сервиса.
4. **Deployment Diagram**: Показывает как система развернута в Kubernetes. Используйте для DevOps и планирования инфраструктуры.
5. **Sequence Diagrams**: Показывают взаимодействие компонентов во времени для конкретных сценариев. Используйте для понимания бизнес-процессов.

View File

@ -129,7 +129,7 @@
#### **Проблема 6: Неэффективное управление задачами для мероприятий**
**AS-IS:**
- Менеджер по продажам вручную составляет "фанкшн" или "меморандум" (Word документ)
- Менеджер по продажам вручную составляет "функшн" или "меморандум" (Word документ)
- В документе описываются все задачи для разных служб:
- Застройка зала (расстановка столов, стульев)
- Предоставление оборудования (проектор, экран)
@ -142,15 +142,15 @@
**TO-BE:**
- Менеджер описывает мероприятие в системе один раз
- Система автоматически создает задачи для каждой службы
- Автоматическая генерация "фанкшн"
- Автоматическая генерация "функшн"
- Все задачи отслеживаются в единой системе
- Массовое создание связанных задач для разных подразделений
**Требование:**
**Требование:**
- Возможность массового создания задач (bulk task creation)
- Описание мероприятия с автоматической декомпозицией на задачи
- Привязка задач к конференц-залам и времени
- Формирование документа "фанкшн" на основе введенных данных
- Формирование документа "функшн" на основе введенных данных
**Примечание:** Функционал, который можно продавать отдельным модулем. Пока не решен полноценно ни одной существующей системой.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,240 @@
<mxfile host="65bd71144e">
<diagram id="7gCwj9mQwRpnqfD4ykJp" name="Page-1">
<mxGraphModel dx="4779" dy="3497" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<object placeholders="1" c4Name="Message Broker" c4Type="Container" c4Technology="Apache Kafka" c4Description="Очередь сообщений" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="2">
<mxCell style="shape=cylinder3;size=15;direction=south;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="-780" y="-40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="connections-service" c4Type="Service" c4Technology="Python" c4Description="Управляет связями между адаптерами системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="3">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-80" y="-200" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="PMS Adapter" c4Type="Service" c4Technology="Python" c4Description="Адаптер передачи сообщений в систему" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="4">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1690" y="-120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Custom Adapter #N" c4Type="Service" c4Technology="Python" c4Description="Адаптер передачи сообщений в систему" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="6">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1410" y="40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="PMS" c4Type="Software System" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#cccccc&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="7">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#8C8496;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#736782;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1690" y="-480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="ERP" c4Type="Software System" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#cccccc&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="8">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#8C8496;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#736782;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1410" y="-480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Housekeeper" c4Type="Software System" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#cccccc&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="9">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#8C8496;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#736782;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1130" y="-480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="tasks-service" c4Type="Service" c4Technology="Python" c4Description="Управляет всеми тасками системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="21">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-360" y="-200" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="БД" c4Type="Container" c4Technology="Postgress" c4Description="Сохранение данных системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="22">
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="-360" y="480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Web admin" c4Type="Container" c4Technology="Typescript, React" c4Description="Админка для управления системой" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="23">
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="-360" y="-960" width="240" height="160" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Service Layer" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="24">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-400" y="-280" width="880" height="600" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Mobile Apps" c4Type="Container" c4Technology="?" c4Description="Отдельные приложения для работников" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="25">
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="-80" y="-960" width="240" height="160" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Telegram Bot" c4Type="Container" c4Technology="?" c4Description="Бот для управления системой" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="26">
<mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="200" y="-960" width="240" height="160" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Client Layer" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="27">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-400" y="-1040" width="880" height="320" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="API Gateway Layer" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="31">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-400" y="-640" width="880" height="280" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="REST API" c4Type="Service" c4Technology="?" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="32">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-360" y="-560" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="gRPC" c4Type="Service" c4Technology="?" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="33">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-80" y="-560" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="WebSocket" c4Type="Service" c4Technology="?" c4Description="" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="34">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="200" y="-560" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="users-service" c4Type="Service" c4Technology="Python" c4Description="Управление пользователями системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="35">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="200" y="-200" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="notification-service" c4Type="Service" c4Technology="Python" c4Description="Управление уведомлениями системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="36">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-360" y="-40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="file-storage-service" c4Type="Service" c4Technology="Python" c4Description="Управление файлами системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="37">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-80" y="-40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="audit-service" c4Type="Service" c4Technology="Python" c4Description="Аудит действий пользователя" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="38">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="200" y="-40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="scheduler-service" c4Type="Service" c4Technology="Python" c4Description="Создание задач по расписанию" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="39">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-360" y="120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="permissions-service" c4Type="Service" c4Technology="Python" c4Description="Управление правами доступа пользователей" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="40">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-80" y="120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="events-service" c4Type="Service" c4Technology="Python" c4Description="Управление мероприятиями" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="41">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="200" y="120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Adapter Layer" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="42">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1730" y="-200" width="880" height="440" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="ERP Adapter" c4Type="Service" c4Technology="Python" c4Description="Адаптер передачи сообщений в систему" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="43">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1410" y="-120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Housekeeping Adapter" c4Type="Service" c4Technology="Python" c4Description="Адаптер передачи сообщений в систему" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="44">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1130" y="-120" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Telegram Bot Adapter" c4Type="Service" c4Technology="Python" c4Description="Адаптер передачи сообщений в систему" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%: %c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="45">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;fontSize=11;labelBackgroundColor=none;fillColor=#23A2D9;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0E7DAD;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1690" y="40" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Data Layer" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="46">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-400" y="400" width="880" height="280" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="Cache" c4Type="Container" c4Technology="Redis" c4Description="Сохранение данных системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="50">
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="-80" y="480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="File Storage" c4Type="Container" c4Technology="S3" c4Description="Сохранение данных системы" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;%c4Name%&lt;/b&gt;&lt;/font&gt;&lt;div&gt;[%c4Type%:&amp;nbsp;%c4Technology%]&lt;/div&gt;&lt;br&gt;&lt;div&gt;&lt;font style=&quot;font-size: 11px&quot;&gt;&lt;font color=&quot;#E6E6E6&quot;&gt;%c4Description%&lt;/font&gt;&lt;/div&gt;" id="51">
<mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
<mxGeometry x="200" y="480" width="240" height="120" as="geometry"/>
</mxCell>
</object>
<object placeholders="1" c4Name="External System" c4Type="SystemScopeBoundary" c4Application="Layer" label="&lt;font style=&quot;font-size: 16px&quot;&gt;&lt;b&gt;&lt;div style=&quot;text-align: left&quot;&gt;%c4Name%&lt;/div&gt;&lt;/b&gt;&lt;/font&gt;&lt;div style=&quot;text-align: left&quot;&gt;[%c4Application%]&lt;/div&gt;" id="52">
<mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
<mxGeometry x="-1730" y="-520" width="880" height="240" as="geometry"/>
</mxCell>
</object>
<mxCell id="55" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="43" target="8">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="56" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="4" target="7">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="57" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="44" target="9">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<object placeholders="1" c4Type="Relationship" c4Technology="e.g. JSON/HTTP" c4Description="e.g. Makes API calls" label="&lt;div style=&quot;text-align: left&quot;&gt;&lt;div style=&quot;text-align: center&quot;&gt;&lt;b&gt;%c4Description%&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center&quot;&gt;[%c4Technology%]&lt;/div&gt;&lt;/div&gt;" id="64">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="39.93" y="-774.5" as="sourcePoint"/>
<mxPoint x="39.56" y="-584.5" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="65">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="39.62" y="-420" as="sourcePoint"/>
<mxPoint x="40" y="-220" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="66">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="39.089999999999996" y="260" as="sourcePoint"/>
<mxPoint x="39.47" y="460" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="67">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="-930" y="20" as="sourcePoint"/>
<mxPoint x="-790" y="20" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="68">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="-790" y="40" as="sourcePoint"/>
<mxPoint x="-930" y="40" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="69">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="-520" y="9.23" as="sourcePoint"/>
<mxPoint x="-380" y="9.23" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
<object placeholders="1" c4Type="Relationship" id="70">
<mxCell style="endArrow=blockThin;html=1;fontSize=10;fontColor=#404040;strokeWidth=1;endFill=1;strokeColor=#828282;elbow=vertical;metaEdit=1;endSize=14;startSize=14;jumpStyle=arc;jumpSize=16;rounded=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1">
<mxGeometry width="240" relative="1" as="geometry">
<mxPoint x="-380" y="29.23" as="sourcePoint"/>
<mxPoint x="-520" y="29.23" as="targetPoint"/>
</mxGeometry>
</mxCell>
</object>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@ -0,0 +1,117 @@
[Назад](/README.md)
# Вопросы по архитектуре TaskManager
## 1. Стандартизация сообщений
- Какие ключевые поля должны быть в стандартизированном сообщении?
- Например: task_id, source_system, target_system, task_type, priority, description, attachments, due_date
- Нужна ли поддержка разных типов задач (одноразовые, периодические, срочные)?
**Ответ:**
1. Пока не думал над контрактом, тк это уже детали. Наверно общие поля стоит указать, как минимум для примера. Но контракт точно поменяется, многое будет зависить от выбора решений.
2. Задачи точно будут одноразовые и периодические
---
## 2. Connections-service
- Связи между системами должны быть двусторонними или направленными?
- Нужна ли поддержка правил маршрутизации (например, "все задачи типа 'уборка' из System_1 идут в System_2")?
- Должны ли связи настраиваться динамически через админку без перезапуска сервисов?
**Ответ:**
1. Сложно сказать, наверное правильнее строить односторонние связи. В случае если нам нужна двусторонняя связь, то мы сперва деляем связь от системы 1 к системе 2, а потом отдельную связь от системы 2 к системе 1. Думаю так будет гибче?
2. Какие то правила наверняка потребуются в будующем, стоит заложится под это, но пока не понятно как это будет
3. Да связи настраиваются динамически через админку и без перезапуска.
---
## 3. Адаптеры
- Какие типы внешних систем предполагаются для первых адаптеров? (PMS системы, ERP, существующие task-менеджеры?)
- Адаптеры должны работать по push-модели (отправляют сами) или pull-модели (периодически опрашивают внешние системы)?
- Нужна ли поддержка WebHooks для интеграций?
**Ответ:**
1. PMS, ERP, управление уборщицами
2. Суть адаптера в том, что он адаптер. Системы бывают очень разные, гдето есть api, гдето надо будет самому пойти в базу, гдето нужно опрашивать систему, гдето система сама будет отправлять данные. Вообщем каждый адаптер будет уникален, но его задача адаптировать сообщения от\из системы в нашу
3. Пока сложно сказать, не понятно применение, какие у тебя идеи?
---
## 4. Tasks-service
- Какие основные статусы задачи? (created, assigned, in_progress, completed, cancelled, rejected?)
- Нужна ли поддержка подзадач и зависимостей между задачами?
- Нужно ли версионирование задач (история изменений)?
**Ответ:**
1. Пока да, но вероятно пользователь захочет созхдавать "свои" статусы. Поэтому вероятно стоит заложится что в MVP делаем стандартынй набор, а потом чтобы смогли поддержать гибкость
2. Между задачами точно появятся зависимости. На счет подзадач не уверен, пока откажемся от них
3. История изменений нужна
---
## 5. Безопасность и разграничение доступа
- Будет ли мультитенантность (несколько отелей в одной инсталляции)?
- Какие основные роли предполагаются? (admin, manager, department_head, worker?)
- Нужна ли изоляция данных между отелями?
**Ответ:**
1. Да отелей у компании может быть несколько
2. админ, техподдержка, и по ролям дальше, все виды сотрудников. скорее всего тоже надо делать настраиваемым, чтобы можно было для отелей настроить свои роли, вдруг там уникальные какието названия
3. Скорее всего нет, так как тот же маркетинг один на всю сетку отелей. Мы все же говорим что отелей несколько, но владелец один. Тоесть между отелями разных владельцев связей не будет!
---
## 6. Масштабирование
- Сколько отелей планируется поддерживать в одной инсталляции?
- Какой объем сообщений в день ожидается (примерно)?
- Kafka будет в одном экземпляре или нужен кластер?
**Ответ:**
1. Может быть разное, от 1 до 50 (а может и больше)
2. Пока не известно, будем проводить НТ после разработки MVP
3. Пока предполагаем одну, кажется должно хватить. Разграничивать сообщения топиками.
---
## 7. Дополнительные сервисы
- **File Storage Service** - где хранить фото/файлы? (S3-compatible, локально, CDN?)
- **Notification Service** - нужны ли уведомления? (email, push, SMS?)
- **Audit Service** - нужен ли отдельный сервис для аудита действий?
- **Scheduler Service** - для периодических задач нужен отдельный сервис?
**Ответ:**
1. s3
2. уведомления нужны: email, push, sms, telegram, max и любые другие месенджеры
3. да аудит нужен
4. scheduler тоже нужен
---
## 8. Технологический стек
- Python сервисы - какой фреймворк? (FastAPI, Django, Flask?)
- Нужна ли REST API Gateway перед всеми сервисами?
- GraphQL рассматривается или только REST?
- Контейнеризация (Docker) + оркестрация (Kubernetes, Docker Compose)?
**Ответ:**
1. Пока не понятно. Это уже детали
2. Rest api нужно для веба. Но еще для веба нужно получать информацию и от сервера. Поэтому вероятно лучше сразу смотреть в grpc + может rest оставить для каких то отдельных запросов
3. Да, скорее всего кластер кубер. Сервисы по контейнерам с возможностью масштабирования подов
---
## 9. Дополнительные вопросы от вас
Есть ли у вас дополнительные требования или ограничения, которые нужно учесть при проектировании?
**Ответ:**
1. Пока наверно все рассказал

12
Проблемы.md Normal file
View File

@ -0,0 +1,12 @@
[Назад](/README.md)
# Список проблем
1. Отсутствие единой системы для передачи задач между подразделениями
2. Невозможность документировать выполнение задач с помощью фото/видео
3. Сложность ввода информации в процессе работы
4. Отсутствие автоматизации повторяющихся задач
5. Отсутствие учета расходных материалов
6. Неэффективное управление задачами для мероприятий
7. Отсутствие контроля процесса уборки номеров
8. Перегрузка ресепшена запросами от гостей

1
Скетч.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 105 KiB