ТЗ: Разработка агента синхронизации данных (Sync Agent)

ТЗ: Разработка агента синхронизации данных (Sync Agent)

Источник файл Ожерельев В.А. ТЗ: Разработка агента синхронизации.md

Дата: 03.05.2026


1. Назначение

Агент синхронизации обеспечивает загрузку и актуализацию данных из Grace CRM в:

Система должна поддерживать:


2. Состав синхронизируемых сущностей

Обязательные сущности:

Сущность Описание
Projects Сделки
Clients Клиенты
Objects Объекты клиента (ключевая связь клиент -> актив)
Activities Активности
Tasks Задачи
Comments Комментарии
Calculations Расчёты / КП
Orders Заказы
Users Пользователи

3. API интеграция с CRM

Основные endpoints

GET /api/projects
GET /api/projects/{id}
GET /api/projects?updated_since=timestamp

GET /api/activities
GET /api/activities?project_id=
GET /api/activities?updated_since=timestamp

GET /api/clients
GET /api/clients/{id}

GET /api/tasks
GET /api/tasks?project_id=

GET /api/comments
GET /api/comments?entity_type=&entity_id=

GET /api/calculations
GET /api/calculations?project_id=

GET /api/orders
GET /api/orders?project_id=

GET /api/users

3.1 Объекты (обязательное расширение CRM)

⚠️ В рамках проекта требуется наличие сущности:

Objects (объекты клиента)

Если отсутствует -- требуется добавить API:

GET /api/objects
GET /api/objects/{id}
GET /api/objects?client_id=
GET /api/objects?updated_since=timestamp

Назначение:

Пример:


4. Архитектура Sync Agent

Компоненты:


5. Mapping схемы OpenSearch (JSON)

5.1 crm-projects

{
  "mappings": {
    "properties": {
      "project_id": {"type": "keyword"},
      "client_id": {"type": "keyword"},
      "object_id": {"type": "keyword"},
      "name": {"type": "text"},
      "status": {"type": "keyword"},
      "stage": {"type": "keyword"},
      "amount": {"type": "double"},
      "manager_id": {"type": "keyword"},
      "created_at": {"type": "date"},
      "updated_at": {"type": "date"},
      "last_activity_at": {"type": "date"},
      "activities_count": {"type": "integer"}
    }
  }
}

5.2 crm-objects (новый индекс)

{
  "mappings": {
    "properties": {
      "object_id": {"type": "keyword"},
      "client_id": {"type": "keyword"},
      "name": {"type": "text"},
      "type": {"type": "keyword"},
      "status": {"type": "keyword"},
      "location": {"type": "text"},
      "created_at": {"type": "date"},
      "updated_at": {"type": "date"}
    }
  }
}

5.3 crm-clients

{
  "mappings": {
    "properties": {
      "client_id": {"type": "keyword"},
      "name": {"type": "text"},
      "industry": {"type": "keyword"},
      "segment": {"type": "keyword"},
      "created_at": {"type": "date"},
      "updated_at": {"type": "date"}
    }
  }
}

5.4 crm-activities

{
  "mappings": {
    "properties": {
      "activity_id": {"type": "keyword"},
      "project_id": {"type": "keyword"},
      "type": {"type": "keyword"},
      "description": {"type": "text"},
      "result": {"type": "text"},
      "created_at": {"type": "date"}
    }
  }
}

5.5 crm-tasks

{
  "mappings": {
    "properties": {
      "task_id": {"type": "keyword"},
      "project_id": {"type": "keyword"},
      "assignee_id": {"type": "keyword"},
      "status": {"type": "keyword"},
      "due_date": {"type": "date"}
    }
  }
}

5.6 crm-comments

{
  "mappings": {
    "properties": {
      "comment_id": {"type": "keyword"},
      "entity_type": {"type": "keyword"},
      "entity_id": {"type": "keyword"},
      "text": {"type": "text"},
      "author_id": {"type": "keyword"},
      "created_at": {"type": "date"}
    }
  }
}
{
  "mappings": {
    "properties": {
      "calculation_id": {"type": "keyword"},
      "project_id": {"type": "keyword"},
      "amount": {"type": "double"},
      "version": {"type": "integer"},
      "created_at": {"type": "date"}
    }
  }
}

5.8 crm-orders

{
  "mappings": {
    "properties": {
      "order_id": {"type": "keyword"},
      "project_id": {"type": "keyword"},
      "amount": {"type": "double"},
      "status": {"type": "keyword"},
      "created_at": {"type": "date"}
    }
  }
}

6. Распределение данных между PostgreSQL и OpenSearch

Данный раздел определяет, какие данные и в каком виде сохраняются в:

Ключевой принцип:


6.0 Диаграмма последовательности обмена данными

sequenceDiagram
    participant CRM
    participant Webhook
    participant SyncAgent
    participant PostgreSQL
    participant OpenSearch

    CRM->>Webhook: project-updated
    Webhook->>SyncAgent: событие

    SyncAgent->>CRM: GET /projects/{id}
    CRM-->>SyncAgent: project data

    SyncAgent->>SyncAgent: transform + normalize

    SyncAgent->>PostgreSQL: upsert
    SyncAgent->>OpenSearch: bulk index

    Note over SyncAgent: update last_sync_timestamp

6.1 Таблица распределения данных

Сущность PostgreSQL (что сохраняется) OpenSearch (что индексируется)
Projects (сделки) Полная структура проекта (raw JSON + нормализованные поля), статус синхронизации, технические поля (sync_state, timestamps) Денормализованная витрина: project_id, client_id, object_id, стадия, статус, сумма, менеджер, last_activity_at, activities_count
Clients (клиенты) Полная карточка клиента, связи, служебные поля Упрощённая витрина: client_id, название, отрасль, сегмент
Objects (объекты) Полная модель объекта, связь с клиентом Витрина: object_id, client_id, тип, статус, локация
Activities (активности) Полные записи активностей (raw), связь с проектом Индекс коммуникаций: тип, текст, результат, дата
Tasks (задачи) Полная структура задач, статусы, SLA Витрина: task_id, project_id, исполнитель, статус, due_date
Comments (комментарии) Полные тексты, связь с entity Индекс текстов для поиска: entity_type, entity_id, текст
Calculations (расчёты) Полные расчёты, версии, параметры Витрина: сумма, версия, привязка к проекту
Orders (заказы) Полная структура заказов Витрина: статус, сумма, дата
Users (пользователи) Полная модель пользователей и ролей Витрина: user_id, роль, команда
Sync metadata offset, updated_since, last_sync_time, retry state ❌ не индексируется
Ошибки / логи sync Полный лог операций ❌ не индексируется

6.2 Принципы формирования витрин OpenSearch

1. Денормализация

В OpenSearch данные агрегируются:

Пример:


2. Обогащение

При индексации добавляются:

Пример:


3. Оптимизация под сценарии поиска

OpenSearch индекс строится под:

НЕ под:


6.3 Поток записи данных

CRM → SyncAgent → PostgreSQL (raw + normalized)
                         ↓
                   Transformer
                         ↓
                  OpenSearch (витрины)

6.4 Ключевые различия слоёв

Критерий PostgreSQL OpenSearch
Тип данных нормализованные денормализованные
Назначение состояние системы поиск и аналитика
Обновление строгое (upsert) bulk indexing
Источник истины да (для AI слоя) нет
Использование Sync, Orchestrator Recommendation, Analytics

6.5 Важное архитектурное требование


7. Модель синхронизации: когда, что и как обновляется

Синхронизация реализуется через 3 параллельных механизма, каждый из которых решает свою задачу:


7.1 Webhooks (near real-time синхронизация)

Назначение

Мгновенная реакция на изменения в CRM.

Когда срабатывает

При событиях в CRM:

Поток

CRM → webhook → SyncAgent → точечный fetch → update

Какие данные синхронизируются

Сущность Что делаем
Projects загружаем 1 проект по ID
Activities загружаем активность или проект целиком
Tasks загружаем задачу
Comments при наличии webhook
Calculations при изменении проекта

Особенность

Webhook не доверяем полностью -> всегда делаем дочитывание через API


SLA


7.2 Polling (инкрементальная синхронизация)

Назначение

Гарантия, что:

Механика

Используется:

GET /api/*?updated_since=timestamp

Частота по сущностям

Сущность Частота Причина
Projects каждые 5 мин ключевая сущность
Activities каждые 5 мин динамика общения
Tasks 5–10 мин SLA
Comments 5–10 мин контекст
Objects 10–15 мин реже меняются
Clients 15–30 мин редко меняются
Calculations 10–15 мин средняя динамика
Orders 10–15 мин финансовые события
Users 1 раз/час почти статично

Поток

Scheduler → SyncAgent → API (bulk) → batch processing → upsert → index

Особенности реализации


SLA


7.3 Full Sync (полная синхронизация)

Назначение


Когда выполняется


Что синхронизируется

Сущность Поведение
Все полная выгрузка
Projects пересборка агрегатов
Activities полная история
Objects восстановление связей
Clients обновление справочника

Поток

Full load → overwrite / reindex → rebuild OpenSearch

SLA


7.4 Приоритет механизмов

Механизм Приоритет Роль
Webhooks высокий скорость
Polling средний надёжность
Full Sync низкий восстановление

7.5 Конфликты и консистентность

Правило:

последнее изменение по updated_at побеждает

Дополнительно:


7.6 Сводная схема

            ┌──────────────┐
            │    CRM       │
            └──────┬───────┘
                   │
      ┌────────────┼────────────┐
      │            │            │
      ▼            ▼            ▼
  Webhooks     Polling     Full Sync
 (реалтайм)   (дельта)     (полный)
      │            │            │
      └──────┬─────┴─────┬──────┘
             ▼           ▼
         Sync Agent (единая логика)
                   │
        ┌──────────┴──────────┐
        ▼                     ▼
   PostgreSQL           OpenSearch

7.7 Ключевой принцип (важно для разработки)

Нельзя полагаться только на один механизм:

➡️ Только вместе они дают:


Итог

Тип данных Как обновляется
Критичные (проекты, активности) webhook + polling
Средние (задачи, расчёты) polling + webhook (если есть)
Справочники (клиенты, users) редкий polling
Связи (objects) polling + full sync

8. Требования к реализации

Обязательные:

Производительность:


9. Ключевые особенности


10. Результат

После реализации:



Revision #1
Created 2026-06-22 03:22:48 UTC by Claude Ops
Updated 2026-06-22 03:22:48 UTC by Claude Ops