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 зелёные.
28 KiB
Дейл (Deal) — Статус разработки и прогресс
Обновляется в конце каждого захода. Проект в git (ветка
main, коммиты на русском) — борд состояния + git-история. Дата последнего обновления: 2026-09-11.2026-09-11 — единый контракт источника (generic source). Ядро (домен Cards, Storage-сервис, персистентность, конвейер, wire, фронт) переведено с Telegram-полей карточки на generic-тип
SourceItem(SourceRef+SourceContent, вложения —DataRef→ общий Storage). Дашборды/канбан/конвейер больше не знают о Telegram; Telegram-специфика — только в тонком адаптере приёма. Tenant-миграции пересозданы с нуля (init). Добавлены extension-pointISourceContentProvider/SourceContentResolverиGET /api/cards/{id}/source. Входящий поток источников — generic (sources.proto/PushSource,SourceIngressGrpcService),PushMessageиз telegram.proto удалён. Сухой прогон текста по конвейеру (стоп-правила → ML → ИИ) без записи:POST /api/admin/check-message+ UI настроек. Remote-просмотр исходника:TelegramService.ReadSource+TelegramSourceContentProvider+ UI «Обновить из источника». Метрика алертингаdeal.ai.budget.used.ratio{tenant}; actor/tenant в access-логе; прогресс переклассификации через SSE. Hardening контейнеров (non-root/read-only/limits), шардированная пакетная миграция схем, единый CI (scripts/ci.sh). Ядро: build 5 sln 0/0,Deal.Tests.Unit1326/1326 PASS, telegram 130/130, ai 52/52, ml 38/38, storage 9/9, фронтbuild+lint:i18nзелёные. Детали —docs/superpowers/specs/2026-09-11-source-contract-design.md.2026-09-11 (вечер) — закрыты остатки код-стайла (TD-COMMENTS-IFACE, TD-STYLE-ANALYZERS). Дедупликация
<summary>: дублей нет (сканы по тексту и по имени члена — 39 интерфейсов/229 членов).var: гейтcsharp_style_var_for_built_in_types = false:warning(ломает сборку), остаток выправленdotnet formatпо 5 sln (51 файл), «очевидный/прочий тип» — silent осознанно. Переводы строк: решено LF —.gitattributes(* text=auto eol=lf),.editorconfig→ lf, нормализовано 1029 файлов; попутно починены 42 CRLF-.sh (первый прогон удалённого CI падал бы). Понижено 12 новых private XML-доков; добавлены 4<summary>членам интерфейсов; переведены 3 англоязычных комментария; из индекса убраны 2__pycache__/*.pyc; STATUS.md — удалён устаревший блок «Осталось (в backlog)» в шапке. Дочистка по контрольному скану краткости: удалены 73 очевидных<param name="ct">(пересказ сигнатуры) в 17 файлах, ужаты 3 summary (многосентенционные/длинные); контроль:<remarks>0, inline-<summary>0, многосентенционных 0, TODO 0. Явные реализации интерфейсов (§11) — остались точечным ревью владельца (43 интерфейса с реализациями, массовая правка не автоматизируется). Сборка 5 sln 0/0; тесты: core 1340/1340, telegram 130/130, ai 52/52, ml 38/38, storage 9/9 — зелёные. Детали —docs/spec/Код-стайл-аудит-2026-09-11.md, §2.2026-09-11 (ночь) — Gitea-контур. Репозиторий запушен (
gitea.khomegeneric.keenetic.pro/rust/Deal), ~4000 спам-пользователей вычищено, регистрация закрыта владельцем. CI перенесён в.gitea/workflows/ci.yml; первый прогон поймал и закрыл кроссплатформенный баг (ModelPoolвалидировал tenant-id черезGetInvalidFileNameChars— на Linux пропускал\); валидация заменена на явный белый список.scripts/исключён из репозитория (правило владельца: в репе только код) — скрипты сборки/тестов/бэкапов/кодмоды живут только локально; CI-workflow переписан inline. Раннер для CI — на сервере рядом с Gitea (пакетdeploy/gitea-runner/).2026-09-11 (поздний вечер) — явные реализации интерфейсов (вариант A, решение владельца). Правило владельца: классы напрямую не вызываем (исключения — DTO, хелперы, экстеншены), тесты — через интерфейсы, моки — NSubstitute, маркерные классы не используем. Сделано: 161 член в 30 прод-файлах переведён на явные реализации codemod'ом
scripts/make_explicit.py; потребители конкретных типов перетипизированы на интерфейсы (8 мест в проде, 17 тест-файлов; самовызовы —((ISessionClient)this)); 10 маркерных классов заменены маркерными интерфейсами (IKanbanModule…ISharedKernel); NSubstitute 6.1.0 подключён к 5 тест-проектам, эталон миграции —FakePasswordHasher→TestHashers.New()(фейк удалён); правила зафиксированы в §11 код-стайла. Card/I*Card— implicit (DTO). Оставшиеся 30 фейков — поэтапная миграция (backlog.md, TD-TESTS-NSUBSTITUTE). Build 5 sln 0/0, тесты зелёные.
Все этапы 0–12 выполнены (100%) — см. roadmap
docs/superpowers/plans/2026-09-05-deal-roadmap.md, план этапа 10docs/superpowers/plans/2026-09-10-deal-stage10-operator-analytics.mdи ledgers в.superpowers/sdd/. Live-приёмки на Docker Desktop выполнены: dev-smoke 14/14, SaaS-контур 15/15, prod-контур+mTLS+ observability PASS, backup/restore на копии PASS, runtime-приёмка этапа 10 (оператор-консоль, аналитика, аудит) PASS (см. чек-лист ниже). Осталось Manual: реальные Telegram/LLM-креды (п.5).
Общий прогресс по этапам
| Этап | Статус | Задач | Тесты (unit, накопительно) | Приёмка |
|---|---|---|---|---|
| 0. Каркас | ✅ готов | 9/9 | 6 | health 200 |
| 1. Доступ и мультитенантность | ✅ готов | 6/6 | 25 | auth 1:1 |
| 2. Settings (настройки) | ✅ готов | 11/11 | 175 | 60/60 |
| 3. Kanban (дашборд) | ✅ готов | 15/15 | 410 | 94/94 |
| 4. Pipeline/«Обработка» | ✅ готов | 13/13 | 535 | 74/74 |
| 5. Projects («Выбранные») | ✅ готов | 13/13 | 620 | 75/75 |
| 6. Сервисы telegram/ml/ai + Discovery | ✅ готов | 20/20 | 830 | 20/20 + 37/37 |
| 7. SaaS-контур (оператор/инвайты/лимиты/аудит/безопасность/prod-деплой/бэкапы/доки) | ✅ готов | 16/16 | 1123 | ✅ live SaaS 15/15 (остальное — ⚠ Manual) |
| 8. Code-quality rework (ревью 5 зон) | ✅ готов | 5/5 фаз | 1139 | build 4 sln 0/0; фронт build OK |
9. Единая карточка (слияние Kanban/Projects, /api/cards+/api/containers) |
✅ готов | 11/11 | 1138 | ✅ live dev-smoke PASS=14 FAIL=0 |
| 10. Оператор-консоль, аналитика, аудит действий, Grafana/Loki-дашборды | ✅ готов | 7/7 | 1173 | ✅ live runtime (Docker dev) |
| 11. Локализация UI (вынос строк в ресурсы) | ✅ готов | 7/7 | 1173 | build + lint:i18n зелёные |
| 12. Наблюдаемость/устойчивость/перф + добивка ТЗ | ✅ готов | 4/4 пакетов + добивка | 1275 | build 4 sln 0/0; telegram 125/125 |
| Итого | этапы 0–12 = 100% | 137/137 | 1275 (core) + 125/52/38 (сервисы) | — |
Финальный прогон этапа 12 (2026-09-10, автономный заход A–D): build Deal.sln 0/0; core 1275/1275 PASS;
telegram 125/125; фронт npm run build зелёный (main-чанк 309 kB, словарь в отдельном чанке i18n),
npm run lint:i18n зелёный; метрики: /metrics (OTel→Prometheus) во всех 4 процессах, Prometheus targets 5/5 UP;
пакеты B (rate-limit/LoginAttemptGuard на Postgres, разлогин suspended, purge) и D (reclassify + токены ML)
с зелёными тестами. Всё остановлено (правило «без хвостов»). LEDGER: .superpowers/sdd/deal-stage12-observability-hardening/.
Финальный прогон этапа 10 (2026-09-10): build Deal.sln 0/0; core 1173/1173 PASS; фронт
npm run build зелёный; GET /api/operator/analytics/{overview,tokens,activity} и
GET /api/operator/audit живьём на dev-Postgres (:5433, миграция AddTokenUsageEvents применена),
deal-core healthy; страницы #/operator и #/join отдаются dev-сервером. Детали — ledger
.superpowers/sdd/deal-stage10-operator-analytics/progress.md.
Финальный прогон (Task 16, 2026-09-08, docker выключен): build 0 warnings / 0 errors всех четырёх sln
(core/telegram/ai/ml); core 1123/1123 PASS, telegram 114/114, ai 50/50, ml 36/36 PASS;
docker compose -f deploy/compose.prod.yml config rc=0 (+ профиль observability);
sh -n scripts/dev-smoke.sh/backup.sh/restore.sh/mtls-certs.sh rc=0.
Накопительный счётчик core в таблице — по состоянию на конец этапа: этап 8 — 1139, этап 9 — 1138 (часть тестов удалена вместе с доменом Projects), этап 10 — 1173.
Что система умеет СЕЙЧАС (проверяемо)
- Ядро (этапы 0–6): вход admin/admin (dev-seed, dev-only), сессии, схемы на тенанта (Postgres :5433);
дашборд (колонки/карточки/drag&drop/архив/корзина/FTS-поиск), «Обработка»
(очередь→стоп-лист→дедуп→ML/ИИ→карточка), «Выбранные» (стадии/напоминания SSE/файлы Local/MinIO),
Настройки (ключи AI enc:, промпты, валюты; Telegram-ключи — глобально у оператора), Каналы/Discovery; полный dev-стек этапа 6 —
deploy/compose.dev.yml(Services__*__UseLocal=false, gRPC-режим telegram/ai/ml + ингресс core). - SaaS-контур (этап 7): оператор (
public.operators/operator_sessions, кукаdeal_operator_session, bootstrap envDEAL_OPERATOR_*; dev-дефолт operator/operator) и ручки/api/operator/*(auth/tenants/invites/limits/audit/health — с этапа 10 у них есть UI, см. ниже); инвайты (код 16 симв., 72 ч) и активацияPOST /api/join(пользователь + провижининг тенанта); лимиты ИИ-бюджета (tenant_limits,TokenUsageRecorder, гейт-декораторы → Local-фолбэк, SSE-тосты 80/100%); append-only аудит; rate limiting (auth 10/мин·IP, api 600/мин·тенант, gRPC-ингресс 600/мин·тенант,LoginAttemptGuard5/15 мин); Origin-проверка мутаций + security-заголовки + ForwardedHeaders за Caddy; mTLS за флагомDEAL_MTLS_*(scripts/mtls-certs.sh→deploy/certs/); Serilog JSON во всех 4 процессах (+ access-логи HTTP/gRPC); prod-деплойdeploy/compose.prod.yml(caddy 80/443, postgres/minio без host-портов, профиль observability: promtail/loki/grafana,.env.prod.example); бэкапыscripts/backup.sh/restore.sh/deal-backup-lib.sh(pg_dump -Fc + MinIO + tar; retention 14). - Оператор-консоль и аналитика (этап 10): hash-роутер фронта (
#/приложение,#/operatorконсоль,#/join?code=…активация инвайта); разделы консоли (вход, тенанты+suspend/resume/impersonate, инвайты, лимиты, аудит с фильтрами/пагинацией, аналитика, health); impersonation ставит httpOnly-кукуdeal_sessionтем же ответом (оператор сразу в тенанте). Сквозной аудит действий (public.audit_log): выходы,invite_joined, действия карточек/комментариев, CRUD контейнеров, настройки, каналы, Telegram. История расхода токеновpublic.token_usage_events+ операторская аналитика (/api/operator/analytics/{overview,tokens,activity},groupBy=day|tenant|provider|model). Grafana provisioning (datasource Loki + дашбордыDeal-Auth/Errors/Rps/Logs) и promtail-лейблы. - Что увидеть глазами: полный dev-стек —
docker compose -f deploy/compose.dev.yml up -d --build→ фронтcd src/frontend && npm run dev→ логинadmin/admin(dev-seed); либо сквозной smoke одной командой:sh scripts/dev-smoke.sh. Prod-контур — §13.8 техдока (оператор → тенант → инвайт →/api/join). Host-режим (Local-заглушки): postgres/minio +dotnet run --project src/core/Deal.Api --urls http://localhost:5080. - Полная карта «что/где» — техдок
docs/technical/Техническая-документация-Дейл.md(§5, §7–§11, §13.1–§13.10), api-mapdocs/api/api-map.md(раздел «Реализовано в Deal»), инструкция пользователяdocs/user-guide/Инструкция-пользователя-Дейл.md.
Manual-чек-лист (остаток после live-приёмок)
Выполнено живьём на Docker (автономно от авто-прогонов Task 16, build/test/config/syntax — там же):
- ✅ SaaS-сквозная приёмка (live, 15/15 PASS) —
run-live-saas.sh+live-saas-check.shна поднятом dev-Postgres (:5433, миграции SystemSaaS + SessionsImpersonationMark применены): оператор login → создать тенанта → инвайт →POST /api/join→ вход пользователя → settings/cards (на тот момент —boards/демо-карточка) → IDOR-негатив 401 (пользователь к операторским ручкам) → suspend (вход 403) → resume (вход 200) → лимиты (tenant_limits) → аудит-лента. Core погашен, :5080 свободен. - ✅ dev-smoke 14/14 PASS — полный gRPC-стек (
scripts/dev-smoke.sh): подъём, health, login admin/admin,/api/tg/statusidle,POST /api/cards(карточкаplanned) → trash → обучающий сигнал spam, ML-флашер выгрузил outbox. Стек погашен скриптом (trap). - ✅ Prod-контур + mTLS + observability (live) — сертификаты перегенерированы (
scripts/mtls-certs.sh -f,) полный набор в deploy/certs; подъёмcompose.prod.yml+--profile observabilityс фиктивными env-секретами (DEAL_MTLS_ENABLED=1, endpoint'ы https://): core/telegram/ai/ml healthy под mTLS; исходящее mTLS подтверждено живьём —/api/tg/status(idle) и/api/ml/status(reachable:true) через Caddy; фронт и/api/healthчерез Caddy 200; promtail→loki (логи пишутся), Grafana 200. Исправлен дефектdeploy/observability/loki.yml(Loki 3.x:delete_request_store)..env.prodтестовый удалён. - ✅ backup/restore (live, на копии) —
backup.sh: pg (-Fc) + minio (docker-mc) + data (tar docker-томов)- retention;
restore.sh pgв копию-БД — 43 таблицы/3 схемы идентичны, данные сошлись (users=2, tenants=2, sessions=30);restore.sh minioс реальным объектом (залит→бэкап→удалён→восстановлен);restore.sh data. Исправлены дефекты скриптов, проявившиеся живьём: двойная схема в MC_HOST_deal (deal-backup-lib.sh), пустой бакет → mv (backup.sh), Windows/MSYS docker-пути (host_docker_path).
- retention;
- ❌ Реальный Telegram-вход (api_id/api_hash/QR) и LLM-вызовы — нужны живые креды.
- ✅ Прогон
scripts/backup.shи restore-тест — см. п.4 (полный цикл на dev-хранилищах и копии-БД). - ✅ Этап 10 — runtime-приёмка (Docker dev-стек) — миграция
AddTokenUsageEventsприменена к dev-Postgres (:5433),deal-coreпересобран/healthy; операторский входoperator/operator→ 200;GET /api/operator/tenants,/audit,/analytics/overview,/analytics/tokens?groupBy=day|provider,/analytics/activity?limit=3→ 200 (реальные лента/агрегаты); фронтnpm run buildзелёный, dev-сервер отдаёт#/operatorи#/join; core-тесты 1173/1173. Детали — ledger этапа 10.
Заделы (этап 13+; подробно — техдок §11 и roadmap)
Единый источник отложенного и техдолга —
docs/superpowers/backlog.md. Ниже — краткая выжимка.
- Этап 11 — Локализация интерфейса (i18n) — выполнен (2026-09-10, урезанный объём): все
пользовательские строки фронта в ресурсах (
src/frontend/src/i18n/, 1039 ключей в 13 областях), линтерnpm run lint:i18n. Переключатель языка и второй язык — в бэклоге: делаем, когда появится потребность (ядро i18n/registerLocaleк этому готово). - Этап 12 — Наблюдаемость/устойчивость/перф — выполнен (2026-09-10, автономно, пакеты A–D):
метрики Prometheus+Grafana (
/metrics:9464 во всех процессах); распределённый rate-limit иLoginAttemptGuardна Postgres; мгновенный разлогин suspended-сессий; авто-purgeaudit_log/tenant_limits; разбиение бандла фронта + прогрессивный рендер колонок; LRU-кэши WTelegram; пакетная миграция схем тенантов; реальныйreclassifyс Local-фолбэком. LEDGER:.superpowers/sdd/deal-stage12-observability-hardening/. - Остатки этапа 12 (закрыто 2026-09-10): доки под этап 12 (real-reclassify, maintenance-migrate, без
демо), Prometheus alert rules (
deploy/observability/prometheus-rules.yml+ провижининг), устранена гонкаFreeTcpPort()в тест-харнессе (единыйTestPort), SSEcards_reclassified(бэк+фронт), нагрузочные скриптыscripts/loadtest/, скан уязвимостей — чисто (core: 0 уязвимых пакетов; frontendnpm audit: 0). - Прочее (требует владельца/кредов): биллинг/провайдер планов и саморегистрация; мультиаккаунтность Telegram;
k8s/Cloudflare; Kafka; экспорт/импорт ML; переключатель языка/второй язык (в бэклоге — по потребности);
реальный Telegram-вход и живые LLM-вызовы;
legacy-прототип
docker-compose.ymlперенесён вarchive/leadradar-legacy/(2026-09-10). - Добивка по ТЗ (2026-09-10, автономно) — закрыты найденные аудитом частично/незакрытые пункты:
ML-проверка на канале/сообщении (
/api/ml/candidates+/apply— реальные, не заглушки); глобальные исключения до ML/ИИ (§5.14); новые группы фильтров колонкиlevels/locations/types/prices(§6.3); «открыть исходник» как быстрое действие на карточке (§6.6); глубины очередей/сессии в/api/operator/health(§10.2); детектор подозрительной активности/api/operator/analytics/suspicious(§10.5); раздел настроек и поддержка тем «Внешний вид» — тёмная (дефолт) / светлая / системная (§8.12). Отчёт аудита:docs/superpowers/reviews/2026-09-10-tz-compliance-audit.md. Core-тесты 1275/1275; фронт build+lint:i18nзелёные. - Telegram-ключи — вариант A (2026-09-10, по решению владельца):
api_id/api_hashзадаёт оператор глобально (таблицаpublic.global_settings, ручкиGET/PUT /api/operator/settings/telegram-keys, hash шифруется; раздел «Telegram» в оператор-консоли). У тенанта ключи убраны — только подключение аккаунта; без ключей подключение недоступно (/api/tg/status → keysSet:false). МиграцияGlobalSettingsприменена;PUTподдерживает частичное обновление (можно сменить одно поле). Core-тесты 1275/1275.
Code-quality rework (2026-09-08, после ревью 5 зон ~1100 файлов)
Проведено многоосевое ревью (безопасность/корректность/архитектура/перф) бэкенда и фронта; findings —
docs/superpowers/reviews/2026-09-08-code-quality-review.md. Все исправления закрыты и проверены:
core 1135/1135, telegram 118/118, ai 52/52, ml 38/38, фронт build OK, 4 sln 0/0. Главное:
- Безопасность: SSRF-гейт (baseUrl каталоговых провайдеров фиксирован + private-IP-блок в проверке), fail-closed Production (rate limit/CORS/conn-string обязательны), код инвайта в аудите — SHA-256, пароль ≥8, маска ключа не перезаписывает ключ и короткие секреты скрыты, TenantId = 32-hex, mTLS fail-closed, gRPC-лимиты входных данных, join проверяет целевого тенанта, атомарный инкремент токенов (Npgsql).
- Корректность: атомарные append комментариев/ссылок/файлов (1 SQL), уникальный objectKey, атомарный дедуп-pump, запрет move из trash/archive/taken, логирование «немых» catch, очистка сессий вне hot-path; фронт: смена пароля с текущим паролем, boot не падает от одного 500, автосейв не затирает промпты, гонки поиска закрыты seq-токенами.
- Архитектура:
Deal.Grpc.Hosting(общая обвязка 3 сервисов),TenantSettingsSnapshot(9 копий чтения настроек → одна), декомпозиция 7 крупных файлов на partial (<350 строк), фронт store.js → слайсыstore/, вынесены компоненты Settings/Discovery; мёртвый код удалён. - Реестры констант (C35, 2026-09-09): общие
Deal.Contracts.Integrations.MlLearningLabels(spam/t:hire/t:order) иSourceDefaults(DefaultHue) вместо дублей в 5 модулях; единый предикат «активные правила» (KanbanColumnRules.HasActiveRules); реестр id-стадийProjectStages(с этапа 9 —CardsDefaultContainers); общийCardsService.JustNowLabel; TTL-эвикция в DiscoverySearchErrorCounter (+4 теста, core 1139). - Заделы (не рисковали без e2e/не успели): вынос оставшихся вкладок SettingsView, Optional-пункты
(пагинация колонок, виртуализация, LRU-кэши WTelegram и др.). Подробности — в отчёте ревью и
.superpowers/sdd/deal-stage8-quality-rework/.
Процесс (обязательства, чтобы не жрать память/хосты)
- Acceptance-серверы — только через враппер с гарантированным kill (taskkill //T //F по PID-файлу) + проверка освобождения порта; в конце каждой приёмки — шаг очистки.
- Контейнеры — по требованию (
docker compose ... up|down); между заходами ничего не держать;scripts/cleanup-dev.sh(kill висящих Deal.*/тест-хостов,dotnet build-server shutdown, остановка deal-контейнеров) — в конце захода. - Хвостов не оставлять (правило владельца, 2026-09-10): по завершении работы все сервисы и процессы
должны быть остановлены — включая Docker-контейнеры и dev-серверы (frontend/Vite, dotnet) — если
владелец явно не попросил оставить их запущенными. Проверка в конце:
docker psбезdeal-*, свободные порты (5173/5080/5082/5101/5102/5103/5433/9000/9001/9464),dotnet build-server shutdown. - Разовые решения — одним списком в начале (правило владельца, 2026-09-10): все вопросы, требующие выбора владельца, собираются и задаются сразу, до начала работы, а не по ходу/в конце. Не спрашивать о том, что уже определено ТЗ/принятыми решениями — это делать без вопросов; вопрос — только при реальном противоречии в требованиях. При неоднозначности без противоречий — выбирать безопасный обратимый дефолт и делать (напр. перенос, а не удаление).
- Легаси-прототип LeadRadar перенесён из корня в
archive/leadradar-legacy/(2026-09-10; обратимо, на сборку/запуск не влияет).