1
Ревью 2026 09 10 tz compliance audit
stepan edited this page 2026-09-13 00:17:00 +03:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Перенесено из репозитория (docs/superpowers/reviews/2026-09-10-tz-compliance-audit.md). Актуальная версия — здесь, в вики.

Аудит соответствия ТЗ «Дейл (Deal) — новая архитектура»

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

Дата: 2026-09-10 Проверяется: docs/spec/ТЗ-дейл-новая-архитектура.md (§1–§12) + расширенные требования этапов 8–12. Метод: только исходный код и артефакты репозитория (C:\telbase). Док-документам на слово не верим — каждое утверждение подкреплено файлом/символом. Единственное запущенное — линтер npm run lint:i18n (быстрый, read-only); остальное не запускалось. Проект не git; правок кода/доков не вносилось, создан только настоящий отчёт.

Сводка

Статус Кол-во
реализовано 131
⚠️ частично 12
отсутствует 1
Всего проверено пунктов 144

Топ-находок — в разделе «Найденные пропуски/расхождения». (Каждая строка таблицы = один проверяемый пункт ТЗ/расширенных требований.)


§1. О продукте

Требование Статус Доказательство
1.1 Приём сообщений из источников в реальном времени src/telegram-service/Deal.Telegram/Dialogs/RealtimeListener.cs (PushMessage + mark-read), Hosting/RealtimeMonitorService.cs
1.2 Отсев мусора (реклама/скам/служебное/дубли/устаревшее) PipelineRejectConstants.cs (stage labels stop/spam_ml/spam_ai/filter_ai/dup/stale), IncomingRules.cs, PipelineWorkerService.Checks.cs
1.3 Структурирование в карточки по профилю (сфера/стек/бюджет/локация) Pipeline/AiCardMapper.cs, Parse/LocalFieldsParser.cs, PipelineCardWriter.cs
1.4 Раскладка по колонкам-фильтрам Kanban/ColumnRules/ColumnRules.cs, CardsService (ContainerAccepts)
1.5 Самообучение на действиях (ML) Kanban/CardsService.Operations.cs (PushAsync на move/trash/restore), MlOutboxFlushScheduler
1.6 Discovery — поиск/подключение источников Deal.Modules.Discovery/*, DiscoveryWorkerService.Search/Evaluate/Join

§2. Термины

Требование Статус Доказательство
2.1 Тенант владеет схемой БД/настройками/ML Data/TenantContext.cs, модель на тенанта (TenantDb миграции), модель ML per-tenant (ml.proto, data/ml/<tenantId>.sqlite)
2.2 Аккаунт Telegram (1 на тенанта) Telegram/Sessions/TenantSession.cs («1 аккаунт на тенанта»)
2.3 Источник (канал/группа/чат) Deal.Modules.Telegram/Application/ITelegramStore.cs, DialogEntity
2.4 Сырое сообщение → очередь Pipeline/Application/Models/QueuedMessage.cs, PipelineIngestService.cs
2.5 Карточка — ядро + модули Deal.Modules.Cards/Application/Card.cs, интерфейсы IContentCard/IBudgetedCard/IContactCard/IFileCard/ITzCard/IRemindableCard/…
2.6 Типы источника (локально/ссылка/файл/Telegram/импорт/API/ИИ/составной) Deal.Modules.Cards/Application/ILocalSource.cs, IWebSource.cs, ITelegramSource.cs, IApiSource.cs, IFileSource.cs, IRowSource.cs, IAiSource.cs, ICompositeSource.cs
2.7 Контейнер + политика Kanban/Application/Models/ContainerPolicyDto.cs, ContainersService.cs
2.8 Отсев с причиной Pipeline/Application/Models/RejectedItemDto.cs, PipelineProcessingService.Rejected

§3. Роли и доступ

Требование Статус Доказательство
3.1 Оператор: тенанты/инвайты/лимиты/health/impersonation с аудитом Endpoints/Operator*, OperatorTenantsEndpoints.Impersonate, AuditEvents.ImpersonationStarted/Stopped
3.2 Тенант: вход по инвайту, пароль, TG-аккаунт, обработка, дашборд Tenants/Application/JoinService.cs, AuthService.cs, Endpoints/JoinEndpoint.cs
3.3 Регистрация только по инвайту IInviteStore, InviteCodeGenerator (16 симв., 72 ч), публичной регистрации нет
3.4 Логин email+пароль, email уникален в SaaS AuthService, users (public), уникальность email
3.5 tenantId — в сессии Models/SessionDto.cs, кука deal_session; JWT не используется (сессии) — допустимо формулировкой «сессии/JWT»
3.6 Вход оператора изолирован от тенантов Configuration/OperatorCookieOptions.cs (deal_operator_session), OperatorAuthEndpoints

§4. Подключение Telegram-аккаунта

Требование Статус Доказательство
4.1 Оператор глобально задаёт api_id/api_hash ⚠️ Ключи хранятся в настройке тенанта tgKeys (SettingsKeys.TgKeys, Deal.Api/Telegram/TelegramKeysService.cs) и задаются в UI тенанта (settings/TelegramTab.vue). Глобальной (операторской) настройки/ручки нет — расхождение с §4.1/§8
4.2 Подключение: QR или телефон+код TelegramTab.vue (qr/phone/code/password), TelegramEndpoints (start-qr/start-phone/submit-code/password), TenantSession.StartQrAsync
4.3 Сессия сохраняется, статус подключения показан Sessions/SessionStore.cs, SessionFileCipher.cs (AES-GCM), TgStatusService, GET /api/tg/status
4.4 1 аккаунт на тенанта (схема допускает расширение) TenantSession (один на тенанта), SessionFarm
4.5 Список диалогов подтягивается при подключении и обновляется на экране + в фоне Dialogs/RealtimeSweep.cs (SyncDialogs каждые 30 с), TelegramEndpoints /dialogs/refresh, ChannelsView.vue
4.6 Вкл/выкл мониторинга по источнику DialogsService.SetMonitorAsync, TelegramEndpoints /dialogs/{id}/monitor
4.7 «Новый чат → мониторинг автоматически» (вкл/выкл) SettingsKeys.AutoMonitorNew, DialogsService.SyncFromTelegramAsync, TelegramStore.SyncFromTelegramAsync
4.8 Удалённые/покинутые источники исчезают TelegramStore.SyncFromTelegramAsync (удаление отсутствующих)
4.9 «Перечитать»: догон ~10 сообщений включённых источников, анти-бан-паузы Dialogs/BackfillService.cs (MessagesLimit=10, паузы 1.53 с / 36 с), POST /api/tg/dialogs/backfill-all
4.10 Полученные сообщения сразу помечаются прочитанными RealtimeListener.OnMessageReceivedAsync (MarkReadAsync после Push), BackfillService (read-ack)
4.11 Discovery: задача поиска → ИИ ключевые слова DiscoveryEndpoints (generate-keywords), IAiTools.GenerateKeywordsAsync
4.12 Поиск каналов, где аккаунт не состоит DiscoveryWorkerService.Search.cs, IsDialogMonitoredAsync
4.13 Каскад: участники → язык → содержание (порог ≥40%) DiscoveryWorkerService.Evaluate.cs, SettingsDefaults.DiscEvalThreshold = 40
4.14 Кандидаты «на рассмотрение» с метаданными/fit/темами/метками (закрытая группа) DiscoveryWorkerService.Constants.cs (MarkClosedGroup…), FinishReviewAsync, Models/DiscoveryTopicDto
4.15 Действия: вручную «Вступить» / авто-вступление с квотами (50/сутки, 50–70 с) DiscoveryBanGuard.cs (DiscJoinLimit=50), DiscoveryPacer.cs (DiscJoinDelayMin/Max=50/70)
4.16 «Отклонить» → чёрный список; список исключает во всех задачах; снимается вручную DiscoveryBlacklistService.cs, DiscoveryBlacklistList.vue, RemoveBlacklistAsync

§5. Обработка входящих (пайплайн)

Требование Статус Доказательство
5.1 Путь: источник → очередь → стоп-лист → дедуп → ML → ИИ → карточка PipelineWorkerService.Pump.cs, SignificantPath, PipelineIngestService
5.2 Этап 1: минимальная длина текста IncomingRules.Evaluate (KindLength), SettingsDefaults.MinLen=24
5.3 Этап 1: стоп-фразы (настраиваемый список) SettingsKeys.StopPhrases, IncomingRules (KindStop), settings/StopTab.vue
5.4 Этап 1: отсев резюме соискателей (настройка) SettingsKeys.BlockResumes/ResumeMarkers, IncomingRules (KindResume, guard «резюме» при маркере найма)
5.5 Этап 1: тип заявки (только вакансии / только заказы) SettingsKeys.WantedType, IncomingRules (KindType), hireMarkers
5.6 Этап 1: дедуп (нормализованный хэш) Parse/DedupHasher.cs, DedupEntries (миграция TenantPipeline)
5.7 Этап 1: устаревшее сообщение → отсев PipelineWorkerService.Checks.cs IsStaleAsync (ArchiveAfterDays)
5.8 ML: уверена → решает сама (спам/колонка); не уверена → ИИ PipelineWorkerService.Pump.cs (run.MlEnabled && !force), ml.proto (take/label/margin)
5.9 Возврат из отсева (force) идёт мимо ML к ИИ Pump.cs (force пропускает ML), PipelineProcessingService.ReturnAsync (Force = true)
5.10 ИИ-фильтр: не про заявки → отсев; выключатель aiFilterEnabled Pump.cs, SettingsKeys.AiFilterEnabled, AiFilterResultDto.Skipped
5.11 Классификация: структурированный разбор (компания/формат/задача/требования/плюсы/условия/бюджет/стек/контакты/тип) Parse/ParsedCardContent.cs, AiCardMapper.cs, ai.proto ClassifyReply
5.12 Назначение колонки с проверкой правил ContainerAccepts, AiCardLearning.cs, ColumnRules.cs
5.13 Глобальный фильтр «без суммы» отдельно для вакансий и заказов SettingsKeys.BudgetRequiredHire/Order, PipelineWorkerService.Checks.cs SkipNoBudgetAsync
5.14 Глобальные исключения по ключевым словам/технологиям/бюджету/локации ⚠️ Глобальных настроек-исключений нет: в SettingsKeys только StopPhrases (стоп-фразы) и per-column exclude (ColumnExclusions.cs). Исключений «ключевые слова/технологии/бюджет/локация» отдельного глобального уровня не найдено
5.15 Карточка — одна строка одной таблицы Cards; ProjectCards упразднена Миграция TenantUnifiedCard.cs (DropTable("ProjectCards") + AddColumn StackJson/LinksJson/FilesJson/HistoryJson/TzText/Reminder…)
5.16 Комментарии — общая таблица LeadComments Миграция TenantKanban.cs (LeadComments), KanbanStore.Comments.cs
5.17 Единый реестр контейнеров; пространства не пересекаются; «взять в работу» = смена контейнера ContainerSpaces.cs, ContainersService.cs, CardsService.Selected.cs (TakeAsync)
5.18 Исходное сообщение хранится и доступно (открыть в Telegram / форматированно) CardDrawer.vue (sourceMsg, tgSourceUrl, renderSourceMessage), ProcessingView.vue

§6. Дашборд (канбан)

Требование Статус Доказательство
6.1 Колонки: «Неразобранное», пользовательские, «Архив», «Корзина» CardIds (inbox/archive/trash), ContainerKinds, KanbanColumns
6.2 Пользователь создаёт колонки; ИИ предлагает с обоснованием; принять/отклонить/переименовать AiSuggestEndpoints, SuggestHeuristics.cs, ContainerColumn.vue (acceptSuggestedBoard, suggested badge)
6.3 Колонка = сложный набор фильтров (ключевые слова/стек/грейд/уровень/цена/бюджет/локация/тип + отрицательные) ⚠️ ContainerRulesDto содержит только Mode/Direction/Keywords/Stack/Grade/Exclude/Budget. Отдельных групп «уровень/цена/локация/тип» нет (частично покрыты direction/keywords); отрицательные — exclude
6.4 При помещении указаны критерии попадания ColumnRules.ComputeHits, MatchHitBuilder, MatchHitDto
6.5 Свежие сверху; drag&drop между колонками с обучением ML KanbanStore.Cards.cs (OrderByDescending(ReceivedAt)), composables/dnd.js, PushAsync on move
6.6 Быстрые действия: комментарий, корзина, контакт, «открыть исходник» ⚠️ Комментарий/корзина/контакт — Card.vue (кнопки). «Открыть исходник» на самой карточке нет — только в CardDrawer.vue и ProcessingView.vue
6.7 Виджеты-счётчики свёрнутых колонок; двигать/менять размер Sidebar.vue, cards.js (cycleWidth, colExtra, reorder), COLUMN_WIDTHS
6.8 Архив: старше N дней (1–30), очистка через 90 дней StorageTickService.cs, SettingsDefaults.ArchiveAfterDays=14 (кламп 1..30), ArchiveClearDays=90
6.9 Корзина: очистка раз в 7 дней; возврат из архива/корзины SettingsDefaults.TrashClearDays=7, CardsService.Operations.cs (RestoreCardAsync)
6.10 «Выбранные»: стадии Запланировано→…→Готово/Отложено CardsDefaultContainers.cs (planned/reply/agree/work/review/ready/hold)
6.11 «Взять в работу» — переход в контейнер, не клон CardsService.Selected.cs TakeAsync
6.12 Модули работы: комментарии/сумма/стек/контакты, ссылки, ТЗ, файлы (S3/MinIO), значки количества CardsService.Files.cs, CardFileKind.cs, FileKindDetector.cs, CardDrawer.vue
6.13 Отложенные: напоминания (срок+время, календарь); выключатель; выключено → не срабатывают CardsService.Reminders.cs (RemindersDisabledDetail, snooze +24 ч), HoldReminderDialog.vue, SettingsDefaults.RemindersEnabled
6.14 История движения — под спойлером CardDrawer.vue (<details> «История движения», historyReversed)
6.15 Ручное создание карточки (пометка «создано локально») CardDetailsEndpoints POST /api/cards, Local флаг, Card.vue/CardDrawer.vue бейдж «Локальная»
6.16 Терминальные зоны «Отклонено»/«Выполнено»; в архив/корзину дашборда не попадают CardsDefaultContainers.finished/rejected (terminal), ContainerPolicyDto.IsTerminal, ClearRejected

§7. Вкладка «Обработка»

Требование Статус Доказательство
7.1 Очередь (этап 1 / ожидают ИИ) с автопрокруткой ProcessingView.vue (таймер-опрос ~2.6 с, статусы etap-1-bez-ii/ozhidaet-ii); «автопрокрутка» реализована как авто-обновление
7.2 Отсев с причиной и источником решения (правила/ML/ИИ/система) + конкретная фраза PipelineRejectConstants.cs (StageLabels/SourceLabels), RejectedItemDto (kw, reason)
7.3 Метаданные, «Открыть исходник», «Исходное сообщение (форматированно)» ProcessingView.vue (metaRows, sourceUrl, srcHtml)
7.4 Полнотекстовый поиск по отсеву PipelineEndpoints /rejected?q= (FTS LIKE), Store поиск
7.5 Возврат из отсева: причины игнорируются, ML/ИИ обучаются, причина возврата PipelineProcessingService.ReturnAsync (Force=true, PushAsync(spam,1.0), returnReason)
7.6 Автоочистка отсева раз в 3 дня; ручная очистка PipelineRejectConstants.RetentionDays=3, POST /pipeline/rejected/clear, DELETE /rejected/{id}
7.7 Счётчик обработки в боковой панели; отсев в панели не показывается Sidebar.vue (state.pQueueCounts.total), отсев — только внутри ProcessingView.vue

§8. Настройки тенанта

Требование Статус Доказательство
8.1 Telegram: ключи приложения (оператор), подключение, авто-мониторинг ⚠️ Подключение/авто-мониторинг (TelegramTab.vue, AutoMonitorNew). Ключи — настройка тенанта tgKeys, а не глобальная операторская (см. §4.1)
8.2 ИИ: провайдер (в т.ч. локальные), модель, ключ зашифрован AiProviders.cs, SettingsService.PatchSecrets.cs (enc:), ISecretCipher
8.3 Промпты: базовый + свой; библиотека по сферам + «мои промпты» PromptLibraryModal.vue (PROMPT_LIBRARY/PROMPT_CATEGORIES, поиск), SettingsService.PatchMyPrompts.cs, AiTab.vue
8.4 ИИ вкл/выкл; ИИ-фильтр вкл/выкл SettingsKeys.AiEnabled/AiFilterEnabled, Pump.cs
8.5 ML: вкл/выкл, обучение на действиях, проверка на сообщении/канале, сброс, самооценка ⚠️ mlEnabled, обучение (PushAsync), predict (сообщение) , сброс (/api/ml/reset), самооценка (MlEvalDto). Проверка на канале не реализована: POST /api/ml/candidates возвращает пустой список (заглушка), POST /api/ml/apply — всегда 404 (MlEndpoints.cs:130155)
8.6 Обработка: стоп-фразы, длина, резюме, тип, домен/ключи, маркеры найма/заказа SettingsKeys.StopPhrases/MinLen/BlockResumes/WantedType/DomainKeywords/HireMarkers, StopTab.vue/ScopeTab.vue
8.7 Колонки: набор, правила, отрицательные фильтры, исключения ContainersEndpoints, BoardRulesDialog.vue, ColumnExclusions.cs (см. замечание 6.3 по составу групп)
8.8 Валюта: целевая, источник (4 запроса/сутки), конвертация при приёме + пересчёт старых (кроме архива/корзины), USDT=USD RatesService.cs (RatesFetchInterval = 6 ч = 4/сутки; USDT→USD), ConversionRecomputer.cs (ConversionExcludedCols archive/trash)
8.9 Хранение: срок архивации (1–30), очистка архива/корзины StorageTickService.cs, SettingsDefaults.ArchiveAfterDays/ArchiveClearDays/TrashClearDays, StorageTab.vue
8.10 Уведомления и напоминания; отложенные — отдельно NotifyTab.vue, SettingsKeys.RemindersEnabled, CardsService.Reminders.cs
8.11 Звук NotifyTab.vue (soundOn, volume, testSound), utils.js (Web Audio) — клиентская настройка, без серверного ключа
8.12 Внешний вид В SettingsView.vue вкладок Telegram/AI/Storage/Stop/Scope/ML/Notify/Currency/Profile — раздела «Внешний вид» (тема/оформление) нет; style.css содержит единственную тёмную тему

§9. Лимиты (бюджет токенов)

Требование Статус Доказательство
9.1 Бюджет токенов на LLM, период настраивается TenantLimitDto (BudgetTokens, Period month/day), OperatorLimitUpdateRequest
9.2 ai-service оценивает вызов в токенах, списывает с бюджета TokenUsageRecorder.cs, BudgetedAiClassifier.cs, BudgetedAiTools.cs, ai.proto Usage
9.3 При исчерпании: fallback + уведомление; приём не блокируется BudgetedAiClassifier (Local-фолбэк), Warned80/NotifiedExhausted, условия pipeline не блокируются
9.4 Оператор видит расход и меняет бюджет OperatorLimitsEndpoints (/limits, /tenants/{id}/limit), AnalyticsService

§10. Админка оператора

Требование Статус Доказательство
10.1 Тенанты: создание, инвайты, статус, лимиты, приостановка OperatorTenantsEndpoints (create/suspend/unsuspend), OperatorInvitesEndpoints
10.2 Health всех сервисов и очередей ⚠️ Сервисы (OperatorHealthEndpoints, ml/ai/telegram по gRPC-пробам). «Очереди» в health нет — глубины очередей публикуются только в метриках (Observability/DealMetricsCollector.cs/metrics)
10.3 Аудит: входы/выходы, инвайты, impersonation, действия оператора и тенанта AuditEvents.cs (login/logout/invite/impersonation/card_/container_/settings/channels/telegram), AuditService
10.4 Аналитика: расход токенов (день/тенант/провайдер/модель) + лента действий с фильтрами AnalyticsService.TokensAsync (groupBy), OperatorAnalyticsEndpoints, AuditSection.vue/AnalyticsSection.vue
10.5 Подозрительная активность (по логам безопасности) ⚠️ Отдельного разбора/детектора подозрительной активности не найдено; есть счётчики неудачных входов в AnalyticsService.OverviewAsync (failedLogins) и общие Grafana-дашборды
10.6 Метрики сервисов (Prometheus/Grafana) DealMetricsHosting.cs (/metrics :9464), deploy/observability/prometheus.yml, prometheus-rules.yml, Grafana-дашборды
10.7 UI: #/operator и #/join router.js, views/operator/OperatorConsole.vue, views/JoinView.vue

§11. Нефункциональные требования

Требование Статус Доказательство
11.1 Безопасность: TLS, mTLS между сервисами scripts/mtls-certs.sh, MtlsCertificates.cs, compose.prod.yml (DEAL_MTLS_*), MtlsOptions.cs
11.2 Параметризованный SQL EF Core / Npgsql по всему Deal.Infrastructure; ручной SQL — параметризованный (ExecuteSqlRawAsync без конкатенации)
11.3 IDOR/XSS/SSRF/CSRF IDOR — session+tenant-scope middleware; XSS — renderSourceMessage (экранирование); SSRF — AiConnectionChecker.cs (IsPrivateEndpoint, allowlist AiProviders), CbrRateSource (fixed URL); CSRF — OriginGuardMiddleware.cs + SameSite
11.4 Argon2id DefaultPasswordHasher.cs (Isopoh Argon2, Variant Argon2id)
11.5 Rate limiting (прокси + приложение), счётчики распределённые в БД StoreBackedFixedWindowRateLimiter.cs, IRateLimitCounterStoreRateLimitCounterStore (public.rate_limit_counters), LoginAttemptGuard.cs, RateLimitPolicies.cs
11.6 Cloudflare ⚠️ В коде нет интеграции/конфигурации Cloudflare; edge — Caddy (deploy/caddy/Caddyfile, TLS internal). Требование внешнего периметра, вне репозитория
11.7 Ежедневные бэкапы (Postgres/файлы/сессии), outbox для событий scripts/backup.sh/restore.sh/deal-backup-lib.sh; outbox — MlOutboxQueue.cs, MlOutboxFlushScheduler.cs
11.8 Авто-очистки (retention аудита/лимитов/счётчиков), разлогин suspended DataRetentionScheduler.cs, DataRetentionOptions.cs; AuthService.ResolveSessionAsync (suspended → null)
11.9 Наблюдаемость: логи → Loki, метрики OTel→Prometheus→Grafana + алерты, token_usage_events Logging/DealLogging.cs, deploy/observability/{promtail,loki}.yml, prometheus-rules.yml; миграция AddTokenUsageEvents
11.10 Масштабируемость: модульный монолит + сервисы ml/ai/telegram; k8s позже Deal.Modules.*, отдельные проекты src/{ai,ml,telegram}-service, compose.*.yml; k8s отсутствует (заявлено позже)
11.11 Производительность: без потерь; анти-бан-паузы не блокируют обработку PipelineIngestService/DedupEntries, фоновые PipelineWorkerScheduler/BackfillService, progressive.js
11.12 i18n: строки вынесены, RU по умолчанию, новые языки, переключение на лету с сохранением, форматтеры дат/чисел/валют, фолбэк RU ⚠️ Ядро i18n есть (i18n/index.js, ru.js/ru.data.js, $t), линтер проходит зелёным (проверено: npm run lint:i18n → ✓). Но: нет UI-переключателя языка, нет второго языка и нет сохранения выбораindex.js прямо: «UI-переключателя на этом этапе нет»); даты/числа форматируются жёстко через toLocale*('ru-RU', …) (store/core.js, store/settings.js, fmtNum в store/operator.js), а не через locale-aware i18n-форматтеры

§12. Ограничения и допущения

Требование Статус Доказательство
12.1 Фронтенд Vue 3 + Vite + Tailwind; единый контракт /api/cards + /api/containers с этапа 9 package.json (vue/vite/tailwind), api.js, CardsEndpoints.cs, ContainersEndpoints.cs
12.2 Данные LeadRadar тестовые — не мигрируются Отдельные миграции Deal; данных-миграций из LeadRadar нет
12.3 Kafka, k8s, биллинг-провайдер, саморегистрация — вне рамок В коде отсутствуют
12.4 1 Telegram-аккаунт на тенанта; несколько — позже TenantSession (1 на тенанта)

Расширенные требования (этапы 8–12)

Требование Статус Доказательство
E1 Библиотека готовых промптов по специальностям ru.data.js PROMPT_LIBRARY (IT/дизайн/недвижимость/стройка/услуги/красота/обучение), PromptLibraryModal.vue
E2 Категории и поиск в библиотеке PROMPT_CATEGORIES, фильтр query/cat в PromptLibraryModal.vue
E3 Раздел «Мои промпты» + свой промпт SettingsService.PatchMyPrompts.cs, AiTab.vue (addMyPrompt/removeMyPrompt), лимит ≤100
E4 Двухэтапный стоп-лист: стоп-фразы без ИИ, затем ИИ-фильтр с возможностью отключить Этап 1 IncomingRules (без ИИ); ИИ-фильтр FilterSafelyAsync под AiFilterEnabled
E5 Исключения внутри колонки ColumnExclusions.cs (veto Exclude), BoardRulesDialog.vue
E6 Discovery: поиск/вступление в каналы и группы DiscoveryWorkerService.Search/Join, DiscoveryOps (telegram-service)
E7 Discovery: квоты/интервалы, закрытые группы, темы, список на рассмотрение DiscoveryBanGuard, DiscoveryPacer, MarkClosedGroup, DiscoveryTopicGroup, статус review
E8 «Перечитать каналы»/backfill, пометка прочитанными, мгновенный приём BackfillService.cs (10 сообщений, паузы), read-ack; RealtimeListener.cs
E9 ML отдельным контейнером src/ml-service/Deal.Ml/Dockerfile + compose.dev.yml/compose.prod.yml (ml-service, gRPC :5103)
E10 ML: обучение на действиях пользователя и ИИ Пользователь — CardsService.Operations.cs (PushAsync(…,1.0)); ИИ — AiCardLearning.cs, CardReclassifier.cs (AiPushWeight)
E11 Отдельная настройка проверки ML на сообщении/канале ⚠️ Проверка на сообщении (POST /api/ml/predict, MLPanel.vue); проверка на канале (/api/ml/candidates — пустая заглушка, /api/ml/apply — 404)
E12 Архив/корзина (сроки, возврат, ручная очистка) StorageTickService.cs, CardsService.Operations.cs, clear-col/DELETE, Restore
E13 Напоминания «Отложено» (календарь, отключение) HoldReminderDialog.vue, CardsService.Reminders.cs, RemindersEnabled
E14 История карточки под спойлером CardDrawer.vue <details> «История движения»
E15 Контакты квалифицированные (tg/phone/email/linkedin/site) Parse/ContactsQualifier.cs (типы tg/phone/email/linkedin/whatsapp/site, дедуп, отбой ботов/сервисных ссылок)
E16 «Открыть исходник» CardDrawer.vue (sourceUrl), ProcessingView.vue
E17 Источник не на карточке (только в деталях) Card.vue показывает лишь бейдж «Локальная»/контакты; канал и исходное сообщение — в CardDrawer.vue
E18 Бюджет: диапазон/вакансия/валюта + конвертация (4 раза в сутки) CardBudget.cs, BudgetNormalizer.cs, RatesService.cs (6 ч = 4/сутки), ConversionRecomputer.cs
E19 Обязательность суммы (опционально для вакансий) SettingsKeys.BudgetRequiredHire/BudgetRequiredOrder, SkipNoBudgetAsync
E20 Вкладка «Обработка» (очередь + отсев + причины + поиск) ProcessingView.vue, PipelineEndpoints
E21 Возврат из отсева с обучением PipelineProcessingService.ReturnAsync (PushAsync(spam,1.0), Force)
E22 Оператор-консоль views/operator/* (Tenants/Invites/Limits/Audit/Analytics/Health), router.js
E23 Аналитика токенов AnalyticsService.cs, OperatorAnalyticsEndpoints.cs, token_usage_events
E24 Аудит входов/выходов/действий (этап 10) AuditEvents.cs, AuditService.cs, AuditSection.vue
E25 i18n (вынос строк) ⚠️ Строки вынесены и линтер зелёный, но нет переключателя языка/второго языка/персистентности и locale-форматтеров (см. 11.12)
E26 Метрики Prometheus DealMetricsHosting.cs, SharedKernel/Observability/DealMetrics.cs, prometheus.yml (таргеты 5/5)
E27 Распределённый rate-limit RateLimitCounterStore.cs (Postgres), StoreBackedFixedWindowRateLimiter.cs, миграция RateLimitCounters
E28 reclassify (реальный, этап 12) CardsEndpoints /reclassify и /{id}/reclassify, CardReclassifier.cs (локальный фолбэк), ReclassifyGate.cs, audit card_reclassified

Найденные пропуски/расхождения

Отсутствует

  1. §8.12 «Внешний вид» (настройки оформления). В SettingsView.vue нет вкладки/раздела внешнего вида; тема одна (тёмная, style.css @theme). Отдельной настройки «внешний вид» не найдено.

⚠️ Частично

  1. §8.5 / E11 «проверка ML на канале». POST /api/ml/candidates (MlEndpoints.cs:131141) возвращает {items: []} с комментарием «До этапа 6 telegram-данных нет» — устаревшая заглушка; POST /api/ml/apply (MlEndpoints.cs:144155) всегда отвечает 404 «Исходное сообщение не найдено». Реального разбора сообщений канала/ручного применения решения ML нет, хотя telegram-данные в системе уже есть (проверка на сообщении — POST /api/ml/predict — работает).
  2. §5.14 «Глобальные исключения по ключевым словам/технологиям/бюджету/локации». Глобальных настроек такого исключения в SettingsKeys нет: есть только stopPhrases (стоп-фразы) и per-column exclude (ColumnExclusions.cs). Исключения уровня «технология/бюджет/локация» как общий фильтр не найдены.
  3. §4.1/§8.1 ключи Telegram. Хранятся как настройка тенанта tgKeys (TelegramKeysService.cs) и вводятся в UI тенанта (TelegramTab.vue). ТЗ требует, чтобы api_id/api_hash задавал оператор глобально — глобальной операторской настройки/ручки нет.
  4. §11.12 / E25 i18n. Строки вынесены в словари (i18n/locales/ru.js, ru.data.js), npm run lint:i18n проходит. Но отсутствуют: UI-переключатель языка, второй язык, сохранение выбора, «переключение на лету» (в i18n/index.js явно сказано «UI-переключателя на этом этапе нет»). Форматирование дат/чисел жёстко ru-RU (store/core.js:232276, store/settings.js:351406, store/operator.js:356), не через locale-aware i18n-форматтеры.
  5. §6.3 состав фильтров колонки. ContainerRulesDto = Mode/Direction/Keywords/Stack/Grade/Exclude/Budget. ТЗ перечисляет также «уровень/цена/локация/тип» отдельными опциями — явных групп нет (частично покрываются direction/keywords).
  6. §6.6 «открыть исходник» как быстрое действие карточки. На Card.vue есть комментарий/корзина/контакт, но ссылки «открыть исходник» нет — она доступна только в CardDrawer.vue и ProcessingView.vue.
  7. §10.2 health очередей. /api/operator/health проверяет БД и сервисы ml/ai/telegram, но глубины очередей (пайплайн, MlOutbox) в JSON health не отдаёт — они только в метриках (DealMetricsCollector.cs/metrics).
  8. §10.5 подозрительная активность. Специализированного детектора/ленты подозрительной активности по логам безопасности не найдено; есть лишь счётчик failedLogins в обзорной аналитике и общие Grafana-дашборды.
  9. §11.6 Cloudflare. В репозитории нет конфигурации/интеграции Cloudflare (edge — Caddy, deploy/caddy/Caddyfile). Требование периметра, вне кода приложения.
  10. §7.1 «автопрокрутка» очереди. Реализована как периодическое авто-обновление списка (~2.6 с, ProcessingView.vue), а не как буквальная авто-прокрутка. Семантически покрывает требование, но не дословно.

Дефекты/легаси, замеченные при проверке (не пункты ТЗ, но влияют на заявленные функции)

  1. NotifyTab.vue — сломан список активных напоминаний. const holdReminders = computed(() => state.projectCards.filter(...)) (settings/NotifyTab.vue:68), при этом state.projectCards больше нигде в src/ не определяется (grep даёт ровно одно совпадение — этот файл). После этапа 9 (projectCards/stage упразднены) обращение к state.projectCards.filter даёт undefined.filter → ошибка рендера вкладки «Уведомления».
  2. Легаси-артефакты LeadRadar. В корне остались docker-compose.yml (сервисы app/ml/minio старого стека), каталог backend/ (python app/) и mlservice/ (python). Текущая архитектура — deploy/compose.*.yml
    • src/{core,ai,ml,telegram}-service. Прямого нарушения ТЗ нет, но это риск путаницы (в STATUS.md «судьба legacy docker-compose.yml» помечена как открытый вопрос).

Чего проверка не покрывает

  • Живые внешние интеграции без кредов. Реальный Telegram-вход (api_id/api_hash/QR) и реальные LLM-вызовы не проверялись (нет кредов; см. STATUS.md, п.5 «нужны живые креды»). Проверяется только наличие кода/контрактов и локальных заглушек.
  • Живой контур Docker/k8s, mTLS-рукопожатие, Grafana/Loki/Prometheus. Проверены конфиги (compose.*.yml, deploy/observability/*) и код обвязки, но не факт поднятия/скрейпа в этой сессии (сервисы не поднимались).
  • Скрипты бэкапа/восстановления и нагрузочные тесты. Наличие и читаемость проверены (scripts/backup.sh, scripts/restore.sh, scripts/loadtest/), но не выполнялись.
  • Корректность чисел в тестах. Тест-счётчики (STATUS.md: core 1203 и т.п.) не пересчитывались — тесты не запускались (кроме быстрого lint:i18n).
  • UI-поведение в браузере. Выводы по фронту основаны на чтении .vue/.js; реальные клики, drag&drop и рендер не воспроизводились.
  • Внешний периметр (Cloudflare, TLS в проде, DNS, egress-контроль). Вне репозитория.
  • Соответствие формальным юридическим требованиям/биллингу — вне рамок ТЗ (заявлено как «позже»).

Обновление (2026-09-10, вечер) — статус после добивки

Часть найденных ⚠️/ закрыта в тот же день (детали — .superpowers/sdd/deal-stage12-observability-hardening/task-tz-*.md):

Пункт Было Стало
§8.12 «Внешний вид» раздел настроек + темы тёмная/светлая/системная (§15 техдока)
§8/E11 ML-проверка на канале ⚠️ заглушка MlReviewService (`/api/ml/candidates
§5.14 глобальные исключения ⚠️ excludeKeywords/Locations/Types/Budget* на стоп-этапе
§6.3 группы фильтров колонки ⚠️ levels/locations/types/prices + matchHits
§6.6 «открыть исходник» на карточке ⚠️ быстрое действие в Card.vue
§10.2 health очередей ⚠️ queues/sessions в /api/operator/health
§10.5 подозрительная активность ⚠️ SuspiciousActivityService + /api/operator/analytics/suspicious

Остаются требующими владельца/кредов (осознанно): глобальные Telegram-ключи оператора (§4.1/§8.1), переключатель языка (§11.12 — в бэклоге, по потребности), живые Telegram/LLM-вызовы, Cloudflare/прод-периметр. Итог после добивки: core-тесты 1245/1245; фронт build + lint:i18n зелёные.