Files
Deal/docs/architecture/2026-09-05-deal-architecture-design.md
T
Rustam Khalimov 195faf1b1f
ci / build-test (pull_request) Successful in 2m56s
ci / build-test (push) Successful in 2m52s
Восстановить docs/ как зеркало для агентов (ревью МР #11)
Ревью rust: перенос в вики не должен удалять из репозитория то, что нужно
агенту для работы (бэклог, статус, планы, код-стайл, спеки). Дублирование
вики и репы разрешено и обязательно: вики — актуальные версии для людей,
docs/ — зеркало для контекста агентов. README разведён по ролям.
2026-09-12 23:54:28 +03:00

20 KiB
Raw Blame History

Дейл (Deal) — архитектурный дизайн-док

Исторический документ (архитектурный дизайн-черновик, 2026-09-05). Актуальное состояние — docs/superpowers/STATUS.md и docs/technical/Техническая-документация-Дейл.md.

Версия: 0.1 (черновик для согласования) Дата: 2026-09-05 Статус: фиксирует согласованные решения по переписыванию LeadRadar в новый продукт «Дейл»


1. Контекст и цели

LeadRadar — рабочий прототип (Python/FastAPI/DuckDB/Vue), проверенный на тестовых данных. «Дейл» — новая реализация: SaaS-продукт, который мониторит Telegram-каналы и группы клиентов, отсеивает рекламу/скам/дубликаты и показывает реальные заказы и клиентов, совпадающих с профилем пользователя (сфера, стек, бюджет). Клиенты подключают свои Telegram-аккаунты.

Цели переписывания

  1. Код, который владелец продукта может поддерживать сам (типизированный .NET вместо Python).
  2. Стабильность и строгость типов, интерфейсов, слоёв — «как сеньор-архитектор».
  3. Мультитенантный SaaS (схема на тенанта) — фундамент для роста до сотен/тысяч клиентов.
  4. Безопасность «с первого дня» (публичный продукт).
  5. Полная документация: ТЗ, инструкция пользователя, техдок — параллельно с кодом.

Не-цели (сейчас)

  • Переписывание фронтенда (Vue остаётся как есть).
  • Kafka/кубер (отложены до реального масштаба; архитектура готова к ним).
  • Биллинг-провайдер (лимиты в ядре, биллинг — позже).
  • Саморегистрация тенантов (только инвайты).

2. Решения верхнего уровня (зафиксированы)

# Решение Выбор
1 Стратегия Big Bang: пишем новый бэкенд целиком; старые данные не мигрируем (тестовые)
2 Фронтенд Vue не трогаем; HTTP-контракт /api/... — замороженная спецификация миграции
3 Архитектура Модульный монолит в core (один процесс, одно sln); сервисы — отдельные процессы/sln
4 Стек .NET (актуальная LTS), C# современный, Postgres
5 Мультитенантность Одна Postgres-БД, схема на тенанта (tenant_<id>.*), системное в public
6 Владение данными Каждый модуль владеет своими таблицами; межмодульно — интерфейсы/доменные события
7 Межпроцессно gRPC + mTLS; шина событий за портом IEventBus (outbox → Kafka позже)
8 Telegram Отдельный telegram-service: ферма сессий, 1 аккаунт/тенант, анти-бан; исполняет команды ядра, ничего не знает о бизнес-логике
9 ML Отдельный ml-service: .NET + ONNX, пул моделей per-tenant, обучение на действиях
10 AI (LLM) Отдельный ai-service: фасад провайдеров, промпты, учёт токенов
11 Клиенты SaaS Подключают свои Telegram-аккаунты и настраивают обработку под свою сферу
12 Доступ тенантов Инвайты: тенанта создаёт оператор, клиент по ссылке задаёт пароль
13 Аутентификация Логин = email + пароль (email уникален глобально); tenantId в сессии/JWT
14 Название «Дейл» (бренд), namespace Deal
15 Код-стайл Документ пользователя + 5 адаптаций; 1 тип = 1 файл; .editorconfig + анализаторы
16 Наблюдаемость Serilog + OpenTelemetry → Grafana + Loki + Promtail
17 Админка Операторская (A): тенанты, лимиты, health, impersonation, аудит
18 Бэкапы Ежедневные: Postgres + minio + сессии
19 Лимиты Бюджет токенов на тенанта (LLM); fallback на ML/локальную обработку
20 Деплой docker compose на своём VPS; Cloudflare перед origin; k8s позже

3. Структура репозитория

src/
  core/                          # МОДУЛЬНЫЙ МОНОЛИТ — один процесс, один sln
    Deal.sln
    Deal.Api/                    # host: Web API (/api-контракт), gRPC-сервер, SSE, DI
    Deal.Modules.Pipeline/       # очередь → стоп-лист → дедуп → ML/ИИ → карточка
    Deal.Modules.Kanban/         # карточки, колонки, правила, архив/корзина
    Deal.Modules.Projects/       # «Выбранные» (проектный канбан)
    Deal.Modules.Discovery/      # поиск каналов, вступление, чёрный список
    Deal.Modules.Settings/       # настройки тенанта, промпты, валюты
    Deal.Modules.Tenants/        # тенанты, инвайты, лимиты, админка
    Deal.SharedKernel/           # Result, доменные события, время, tenant-контекст
    Deal.Infrastructure/         # Postgres, миграции, outbox, IEventBus, файлы (MinIO)
    Deal.Contracts/              # DTO для /api + gRPC-контракты наружу
    tests/                       # Deal.Tests.* (unit/integration модулей)

  ml-service/                    # Deal.Ml.sln — .NET + ONNX, обучение/предсказание per-tenant
  ai-service/                    # Deal.Ai.sln — LLM-фасад, промпты, учёт токенов
  telegram-service/              # Deal.Telegram.sln — ферма сессий, анти-бан

  contracts/                     # общие .proto (gRPC): ml.proto, ai.proto, telegram.proto
  frontend/                      # Vue — переезжает как есть
  docker-compose.yml             # dev-подъём всех процессов

Правила:

  • core — единственное место с бизнес-логикой и БД.
  • Каждый сервис самодостаточен: свой sln, свой контейнер.
  • .proto — единственный общий «язык» между процессами, лежит в contracts/.

4. Мультитенантность

Модель БД

  • Одна Postgres-БД, схема на тенанта: tenant_<id>.*.
  • Системные таблицы (реестр тенантов, пользователи, инвайты, глобальные настройки, ключи приложения Telegram) — в схеме public.
  • DAL получает схему из tenant-контекста (claim в JWT / gRPC-метаданные); пул соединений переключает search_path.
  • Миграции применяются ко всем схемам тенантов (специальный механизм, см. §10).
  • «Золотым» клиентам позже — выделенный инстанс: стратегия выбора схемы/БД в одном месте.

Изоляция (критично)

  • tenantId только из сессии/JWT, никогда из тела запроса.
  • Каждый SQL-запрос исполняется в контексте схемы тенанта; модуль проверяет принадлежность объекта тенанту (IDOR-защита).
  • Интеграционные тесты на перекрёстный доступ тенантов — обязательны.

Обработка per-tenant

  • Настройки обработки (стоп-фразы, промпты, колонки/правила, ключи) — per-tenant.
  • ML-модель — per-tenant (модель дизайнера не учится на действиях кровельщика): ml-service держит пул моделей, core передаёт tenantId в каждом вызове.

5. Модули core и их границы

Модули заводятся сразу как отдельные проекты; внутренние интерфейсы между ними не выдумываются заранее — появляются в момент реальной зависимости.

Модуль Ответственность Владеет таблицами (в схеме тенанта)
Pipeline очередь входящих → стоп-лист → дедуп → ML/ИИ → карточка; отсев; обработка очередь, отсев, dedup
Kanban карточки, колонки, правила, архив/корзина, комментарии, файлы карточки, колонки
Projects «Выбранные»: свой канбан, стадии, история, напоминания проекты
Discovery задачи поиска каналов, кандидаты, чёрный список, квоты discovery-таблицы
Settings настройки тенанта, промпты, валюты настройки
Tenants тенанты, пользователи, инвайты, лимиты, аудит, операторская админка tenant-реестр (в public)

Общие справочники (например, «колонки» нужны и Pipeline при создании карточки, и Kanban при отрисовке) живут в модуле-владельце (Kanban); доступ — через его публичный интерфейс.


6. Контракты

6.1 /api — замороженный контракт миграции

  • Фронтенд Vue продолжает ходить в /api/... без изменений.
  • Снимаем точную карту с работающего LeadRadar (эндпоинты + формы ответов, которые реально потребляет фронт) → фиксируем как OpenAPI-спецификацию.
  • Новый Deal.Api обязан воспроизводить её 1:1.
  • Ведём реестр «кривых мест»: если правка фронта на 1 строку убирает слой костылей — выносим на решение владельца по одному (не молча).

6.2 gRPC-контракты (contracts/)

  • telegram.proto: команды ядра (подключить аккаунт, слушать канал, перечитать, вступить/выйти) + поток сырых сообщений → ядро.
  • ml.proto: predict (текст → решение), train (действие → обучение), health.
  • ai.proto: classify/filter/generate (текст → структура), учёт токенов.
  • Каждый вызов несёт tenantId; сервисы проверяют принадлежность по своей модели (сессии/модели), не доверяя полю на слово.

6.3 Шина событий

  • Порт IEventBus в SharedKernel.
  • Реализация сейчас: outbox в Postgres (транзакционно событие + эффект, фоновый диспетчер).
  • Kafka — позже, сменой реализации без правки бизнес-логики.

7. Сервисы

7.1 telegram-service

  • Отдельный процесс, свой sln. Ничего не знает о данных и бизнес-логике.
  • Сессии привязаны к тенанту (tenantId → session, 1:1): команды исполняются только на сессии своего тенанта; нет сессии для tenantId → отказ.
  • Проверка принадлежности диалога: read/subscribe только для диалогов аккаунта тенанта.
  • Join — только от имени тенанта, под его квотами и анти-баном.
  • Исходящий поток сообщений помечен tenantId (источник определён на входе, в сервисе).
  • Сервисная аутентификация (mTLS) + аудит команд (tenantId, действие, диалог, результат).
  • Один аккаунт на тенанта на старте (связь тенант→аккаунты уже таблицей — расширение позже).

7.2 ml-service

  • .NET + ONNX (не ML.NET для онлайн-обучения): пул моделей по тенантам, обучение на реальных действиях пользователя и результатах ИИ.
  • Ничего не знает о домене: получает текст, отдаёт решение; обучение — по контракту.
  • Экспорт/импорт моделей — по контракту (для переноса между инстансами).

7.3 ai-service

  • Фасад LLM-провайдеров (DeepSeek и др., включая локальные OpenAI-совместимые), библиотека промптов, классификация, генерация.
  • Учёт токенов: каждый вызов оценивается в токенах и списывается с бюджета тенанта.
  • При исчерпании бюджета — fallback на ML/локальную обработку + уведомление (приём сообщений не блокируется).

8. Безопасность

Слой приложения (core)

  • SQL-инъекции: запрет конкатенации SQL; только параметризация (EF Core/Dapper); анализаторы; Postgres-роль без DDL.
  • Tenant-изоляция (IDOR): tenantId из сессии; проверка принадлежности; тесты.
  • Аутентификация: Argon2id, лимит попыток, одноразовые инвайты с expiry.
  • Сессии: httpOnly cookie + CSRF (не localStorage).
  • XSS: экранирование на фронте (renderSourceMessage), CSP, запрет v-html без санитайзера.
  • SSRF: ai/telegram не тянут произвольные URL от имени тенанта (allowlist).
  • Валидация входа: DTO + FluentValidation, лимиты размеров.
  • Аудит: входы, инвайты, impersonation, действия оператора — неизменяемый поток.

Транспорт/сервисы

  • TLS везде; mTLS между сервисами; service-token второй фактор.

Инфраструктура

  • Cloudflare (DDoS/WAF) → reverse proxy (TLS, rate limit по IP, security-заголовки).
  • Rate limiting в приложении по тенанту (защита от «шумного соседа»).
  • Docker: сервисы в изолированной сети, наружу — только прокси; non-root, read-only FS.
  • Секреты: env/secret-хранилище; шифрование (enc); ничего в коде/репозитории.

Процессы

  • CI: сканирование зависимостей (NuGet/npm), SAST, trivy-скан образов.
  • Обновления и алерты на CVE.
  • Postgres: бэкапы ежедневные, тест восстановления.

9. Наблюдаемость, админка, бэкапы

Observability

  • Serilog (структурированные логи) + OpenTelemetry (метрики/трейсы) → Promtail → Grafana + Loki.
  • Дашборды: health сервисов, pipeline, ML-качество, расход токенов по тенантам.
  • За абстракцией экспорта — смена стека без правки кода.

Операторская админка (только оператору)

  • Создание тенантов и инвайтов, лимиты, health, impersonation (с полным аудитом), подозрительная активность. Отдельный защищённый вход (оператор ≠ тенант).

Бэкапы

  • Ежедневно: Postgres (pg_dump), файлы MinIO, сессии telegram.
  • Retention и внешняя выгрузка — уточнить на этапе деплоя.

10. Деплой

  • docker compose на одном VPS: core, ml-service, ai-service, telegram-service, postgres, minio, grafana/loki/promtail, reverse proxy.
  • Сервисы compose = будущие k8s-деплойменты (никаких завязок на compose в коде).
  • Миграции схем тенантов: механизм «миграция ко всем схемам» (список схем в public, применение по очереди, версия миграции на схему) — детализировать в плане реализации.

11. Стандарты кода

  • Код-стайл: C:\telbase\Стиль_кода.docx + согласованные адаптации (без snake_case-хелперов и регионов, public-поля → свойства, XML-doc для public-контрактов, настройки через IOptions<T>, комментарии на русском).
  • 1 тип = 1 файл (класс/record/struct/enum/interface — отдельный файл).
  • .editorconfig + Roslyn-анализаторы с ошибками на нарушения.
  • Второй слой правил: скилы agent-rules-books (Clean Code, DDD, DDIA).
  • .NET-эталоны: скил dotnet-clean-architecture-skills (адаптировать под проект).

12. Открытые вопросы / следующие шаги

  1. Карта /api: снять точную спецификацию с работающего LeadRadar (отдельная задача).
  2. Детали лимитов: механика «бюджет токенов» (период, пороги, уведомления) — спроектировать.
  3. Бэкапы: точная схема retention/внешнего хранилища.
  4. Миграции на 1000 схем: детальный механизм.
  5. Порядок реализации: этап 0 (каркас) → Pipeline+Kanban → ai/ml/telegram → Projects/Discovery.

Приложение: глоссарий

  • Тенант — клиент SaaS (одна организация/пользователь), владеет схемой БД и настройками.
  • Канал/источник — Telegram-канал/группа, который слушает аккаунт тенанта.
  • Карточка — структурированная заявка (заказ/вакансия), созданная пайплайном.
  • Outbox — паттерн надёжной доставки событий через таблицу в той же транзакции.