ci / build-test (push) Canceled after 0s
SaaS-мониторинг Telegram: ядро (модули Cards/Kanban/Pipeline/Tenants/Settings/ Discovery, Api, Infrastructure), сервисы telegram/ai/ml/storage, фронт Vue, контракты и grpc-hosting, деплой-конфиги (dev/prod/observability/CI-раннер), Gitea Actions CI, документация (ТЗ, техдок, api-map, код-стайл, планы, бэклог). Текущее состояние: все этапы роадмапа 0–12 закрыты, сборка 5 sln 0/0, тесты 1340/130/52/38/9 зелёные.
273 lines
20 KiB
Markdown
273 lines
20 KiB
Markdown
# Дейл (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** — паттерн надёжной доставки событий через таблицу в той же транзакции.
|