# Дейл (Deal) — Roadmap этапов (все этапы 0–7 выполнены; 2026-09-08) > Исторический документ (roadmap этапов 0–7, 2026-09-08). Актуальное состояние — `docs/superpowers/STATUS.md` и `docs/technical/Техническая-документация-Дейл.md`. > Назначение: зафиксировать план продолжения разработки «Дейл» по этапам. Каждый этап исполняется > как отдельный SDD-план (файл в `docs/superpowers/plans/`, ledger в `.superpowers/sdd//`), > задача-за-задачей с ревью. Проект НЕ git — фиксация в отчётах и ledgers. ## Выполнено - **Этап 0 — Каркас** (`2026-09-05-deal-scaffold.md`): структура `src/`, фронт переехал в `src/frontend/`, `.editorconfig`+`Directory.Build.props`, `Deal.sln` (11 проектов), тесты, dev-Postgres (:5433), tenant-контекст (`TenantId`/`ITenantContext`/`TenantContext` AsyncLocal/`ConnectionStringProvider` search_path), EF (public), `TenantSchemaMigrator`, CI-скрипты. - **Этап 1 — Доступ и мультитенантность** (`2026-09-05-deal-stage1-tenancy.md`): карта `/api` (`docs/api/api-map.md`, 101 эндпоинт, 87 использует фронт), два DbContext (системный `public` + бессхемный tenant: таблица `settings`), миграции InitialSystem/InitialTenant, модуль Tenants (порты+адаптеры, Argon2id, сессии 30 дней), auth-эндпоинты 1:1 (login/logout/me/change-password), SessionMiddleware + `ITenantContext.Reset`, `TenantProvisioningService` (схема `tenant_<32hex>` + Migrate c `MigrationsHistoryTable("__TenantMigrationsHistory", schema)`), `TenantBootstrapService` (seed: тенант id `000…001` + admin/admin из env; идемпотентно). 25 тестов PASS. - **Этап 2 — Settings (настройки тенанта)** (`2026-09-05-deal-stage2-settings.md`): модуль `Deal.Modules.Settings` (каталог ключей/дефолты 1:1 с прототипом, ISettingsStore, SettingsService снимок+PATCH 1:1, IncomingRules, PromptFiller, RatesService) + адаптеры (SettingsStore на `settings`, AesGcmSecretCipher), эндпоинты GET/PATCH `/api/settings`, POST `/api/ai/check`, GET `/api/rates`, POST `/api/rates/refresh`, `/api/ml/*` (заглушка LocalMlClient), POST `/api/admin/check-message` (тестер фильтров). Секреты AI/Telegram — AES-GCM (`enc:` в БД, ключ env `DEAL_ENCRYPTION_KEY`/файл). Задачи 1–11 приняты: 175 unit-тестов PASS, build 0/0, сквозная curl-приёмка :5080 PASS=60 FAIL=0 + psql (шифрование, внутренние ключи не публикуются). **Ограничение:** Settings-экран обслуживается бэкендом, но Vue-фронт полностью оживает только с этапом 3 (его `boot()` требует `/api/boards`, `/api/leads`, `/api/projects`, `/api/tg/status`, `/api/columns/state`; Telegram-вкладка, кнопки «Проверить правила сейчас»/«Пересобрать индекс», «Предложить ключи» и канбан-фронт — этапы 3–6). - **Этап 3 — Kanban (дашборд): колонки, карточки, архив/корзина** (`2026-09-05-deal-stage3-kanban.md`): миграция TenantKanban (Boards/Cards/LeadComments/CardMoves/MlOutbox в схеме тенанта), модуль `Deal.Modules.Kanban` (доски/карточки/правила `ColumnRules` с matchHits, StorageTickService + фоновый StorageTickScheduler 30 с, ConversionRecomputer, демо-фабрика, эвристика ИИ-предложений), эндпоинты boards/columns/leads/search/events(SSE)/admin/demo/ai-suggest, boot-заглушки /projects и /tg/status, LocalMlClient+PushAsync. Задачи 1–15 приняты: 410 unit-тестов PASS, build 0/0, сквозная curl-приёмка :5080 PASS=94 FAIL=0 + psql. **Ограничения:** pipeline/очередь/отсев/FTS — этап 4; projects/файлы/reminder_due — этап 5; реальные ai/telegram/ml и discovery — этап 6; reclassify и /admin/fts/rebuild — контракт-заглушки. Фронт теперь boot'ится полностью и канбан-дашборд работает на демо-данных (реальные данные появятся с pipeline этапа 4). - **Этап 4 — Pipeline + вкладка «Обработка»** (`2026-09-05-deal-stage4-pipeline.md`): миграция TenantPipeline (QueueItems/RejectedItems/DedupEntries + FTS-колонки SearchTsv на Cards/RejectedItems), модуль `Deal.Modules.Pipeline` (ядро разбора 1:1, Ingest/ProcessingService/PipelineWorkerService pump 1:1, CardComposer через `IKanjStore.AddCardAsync`, dedup-связь), порт `IAiClassifier` + детерминированный `LocalAiClassifier`, эндпоинты `/api/pipeline/*` + демо-ingest, реальные admin/tick и admin/fts/rebuild (+SSE new_lead/тост очистки отсева), фоновые PipelineWorkerScheduler (2 с) и purge-отсева 3 дня в StorageTickScheduler, FTS-поиск `/api/search`. Задачи 1–13 приняты: **535 unit-тестов PASS**, build 0/0, сквозная curl-приёмка :5080 (Task 13 — финал) PASS=74 FAIL=0 + psql. **Ограничения:** projects/reminder_due/файлы — этап 5; реальные ai/telegram/ml-сервисы и их gRPC-ингресс, discovery, ИИ-предложения колонок на реальных данных — этап 6; оператор/лимиты/ аудит — этап 7. Вкладка «Обработка» и канбан-дашборд работают на реальном конвейере (демо-ingest до telegram-этапа 6). - **Этап 5 — Projects («Выбранные»): стадии, напоминания, файлы/ссылки, история** (`2026-09-05-deal-stage5-projects.md`): миграция TenantProjects (`ProjectCards` с partial UNIQUE LeadId), модуль `Deal.Modules.Projects` (стадии ProjectStages 1:1, ProjectsService: take из дашборда с уходом лида в `col='taken'`/ручное создание/patch presence-aware/move+история/clear-rejected/ комментарии/ссылки; ProjectReminderService; ProjectFilesService), порт `IFileStorage` + адаптеры `LocalFileStorage`/`MinioFileStorage` (deal-minio в compose.dev.yml), эндпоинты `/api/projects*` (16 шт., файлы и напоминания включены), boot-заглушка /projects снята, напоминания в admin/tick + фоновый 30-с цикл StorageTickScheduler + SSE `reminder_due`. Задачи 1–13 приняты: **620 unit-тестов PASS**, build 0/0, сквозная curl-приёмка :5080 (Task 13 — финал) PASS=75 FAIL=0 + psql (take- семантика, история, clear-rejected, UNIQUE LeadId, файлы на диске, reminder_due фоновым циклом). **Ограничения:** реальные ai/telegram/ml-сервисы и их gRPC-ингресс, discovery, telegram-вкладка и `/tg/status` — этап 6; оператор/лимиты/админка, мульти-аренда MinIO-бакетов — этап 7. - **Этап 6 — Сервисы telegram/ai/ml (отдельные процессы) + Discovery** (`2026-09-05-deal-stage6-services.md`): gRPC-контракты в `src/contracts/*.proto` (общий `Deal.Proto`); три автономных процесса — telegram-service (:5101: ферма сессий 1 акк/тенант, QR-вход, AES-GCM-сессии `/data/sessions`, диалоги/мониторинг/backfill с анти-бан-паузами), ai-service (:5102: LLM-фасад OpenAI-совместимых+Anthropic, Filter/Classify/ GenerateKeywords/EvaluateFit, usage), ml-service (:5103: инкрементальный наивный Байес 1:1 с python `mlservice/model.py`, SQLite на тенанта); core — gRPC-ингресс telegram :5082 (PushMessage→очередь, SyncDialogs, ReportStatus→SSE), модуль Telegram (Dialogs/TgMessages) + эндпоинты /api/tg (14 шт., реальный статус, QR-SVG) вместо boot-заглушки, ai/ml-gRPC-адаптеры за флагами `Services:*:UseLocal` (код-дефолт Local, compose.dev.yml — false), MlOutboxFlushScheduler (10 с), модуль Discovery (воркер 5 с: поиск/ каскад оценки/авто-join с квотами и бан-гардом; /api/discovery 13 шт.); полный dev-стек — `deploy/compose.dev.yml` (postgres/minio/3 сервиса/core, secrets, healthcheck), smoke-скрипт `scripts/dev-smoke.sh` (отложенный живой прогон — Docker Desktop был выключен). Задачи 1–20 приняты: **830 unit-тестов PASS**, build 0 warnings / 0 errors всех четырёх sln, curl-приёмки Task 14 (/api/tg PASS=20 FAIL=0) и Task 19 (/api/discovery PASS=37 FAIL=0), in-proc gRPC-приёмки. Ledger: `.superpowers/sdd/deal-stage6-services/`. **Ручные проверки (с кредами):** Telegram-вход (api_id/api_hash/QR) и реальные LLM-вызовы; живой smoke `scripts/dev-smoke.sh` — после поднятия Docker. **Ограничения этапа 6 (переходят в этап 7):** mTLS-сертификаты и prod-compose; лимиты/бюджеты токенов (учёт `aiTokenUsage` уже есть); оператор/админка/аудит-поток; rate limiting gRPC; экспорт/импорт ML-моделей; ротация/бэкап ключей сессий; reclassify на реальном ИИ (контракт-заглушка остаётся). - **Этап 7 — SaaS-контур (Tasks 1–16, 2026-09-08)** (`2026-09-05-deal-stage7-saas.md`): оператор (`public`-таблицы, кука `deal_operator_session`, bootstrap env, ручки `/api/operator/*` — API-only), инвайты + активация `POST /api/join`, лимиты ИИ-бюджета с fallback-декораторами и SSE-тостами, append-only аудит-поток, rate limiting (приложение + gRPC-ингресс + защита входа), Origin-проверка/ security-заголовки/ForwardedHeaders, mTLS за флагом DEAL_MTLS_* + `scripts/mtls-certs.sh`, Serilog JSON во всех 4 процессах, prod-деплой `deploy/compose.prod.yml` (caddy 80/443, mTLS-env, healthcheck'и grpc_health_probe, профиль observability: promtail/loki/grafana) + `deploy/.env.prod.example`, бэкапы `scripts/backup.sh`/`restore.sh` (+ `deal-backup-lib.sh`). **Task 16 (финал)**: актуализированы техдок §5/§7–§11/§13 (фактический стек, Manual-пометки), api-map (раздел «Реализовано в Deal»), user-guide, STATUS.md (этапы 0–7 = 100%). Финальный прогон: core **1123/1123 PASS**, telegram 114/114, ai 50/50, ml 36/36 PASS, build 0/0 всех четырёх sln, `compose.prod.yml config` rc=0, `sh -n` скриптов rc=0. Ledger: `.superpowers/sdd/deal-stage7-saas/`. **Manual (нужен docker/живые креды):** применение system-миграции + сквозная SaaS-curl-приёмка, подъём compose.prod и dev-smoke `scripts/dev-smoke.sh`, mTLS-рукопожатие контейнеров, реальные Telegram/LLM-вызовы, прогон `scripts/backup.sh` и restore-тест — чек-лист в task-16-report.md. ## Эталонные конвенции (уже в коде — их придерживаться дальше) - Модуль = чистый проект (SharedKernel/Contracts): порты (интерфейсы) + record-DTO, без EF. Регистрация: `AddTenantsModule()` (модуль), адаптеры EF — в `Deal.Infrastructure` через `AddDealPersistence()` (scoped). HTTP-эндпоинты — в `Deal.Api/Endpoints/*` (`MapXxxEndpoints`). - Два EF-контекста: системный (public, явная схема) и tenant (бессхемный; новые таблицы модулей — DbSet в `TenantDbContext` + `dotnet ef migrations add X --context TenantDbContext`; применяются провижинером ко всем схемам). Ошибки API — `{detail}`; JSON camelCase; кука `deal_session`. - Константы/настройки: `IOptions`; без магических чисел; 1 тип=1 файл; XML-doc на public. ## Следующие этапы (после этапов 0–7; порядок из архитектуры §12.5) > **Актуальный источник отложенного и техдолга — `backlog.md` в корне** (роудмап черпается оттуда). > Ниже — историческая секция роудмапа. > Этапы 0–7 выполнены (см. «Выполнено»). Ниже — следующие инкременты: заделы этапа 7 (сознательно > вынесены, подробно — техдок §11) и пункты архитектуры, не входившие в этапы. ### Этап 8+ — следующие инкременты (заделы этапа 7, подробно — техдок §11): - **Этапы 8–10 выполнены** (2026-09-10): ревью/качество; единая карточка (unified card); оператор-консоль + активация инвайта (UI) + аудит действий и аналитика расхода токенов + ELK/Loki-дашборды. - Остаются заделы: OTel-метрики/Prometheus и дашборды метрик (сейчас Serilog-логи → Loki); multi-instance rate-limit и бэкенд попыток входа; экспорт/импорт ML-моделей; reclassify на реальном ИИ; мультиаккаунтность Telegram; биллинг/планы; k8s/Cloudflare-конфигурация; purge-автоматика audit_log. ### Этап 11 — Локализация интерфейса (i18n) **Требование владельца (2026-09-10).** Весь интерфейс — на русском; все тексты вынесены в ресурсы, чтобы можно было добавлять новые языки и менять язык **на лету**. - **Русский — язык по умолчанию.** Все пользовательские строки UI (экраны, кнопки, подписи, пустые состояния, подсказки, подтверждения, уведомления/тосты, страницы оператора и активации) — на русском. - **Никакого хардкода строк в компонентах.** Все тексты — в словарях ресурсов (ключ → значение), включая сообщения об ошибках, которые сейчас формируются на бэке (`{detail}`), — они должны быть локализуемы (ключ + параметры) или переводимы по коду. - **Переключение языка на лету**, без перезагрузки страницы; выбранный язык сохраняется (localStorage/настройки). - **Расширяемость:** добавление нового языка = новый файл словаря, без правок компонентов. - **Форматирование** дат/времени/чисел/валют — через i18n-форматтеры (не вручную), плюрализация — через правила языка. - Ключи — стабильные, сгруппированные по областям (nav/cards/settings/operator/…); отсутствующий ключ в языке → фолбэк на русский. - Бэк: ответы API остаются с `{detail}`/кодами; фронт отображает локализованный текст по коду/ключу (при необходимости — расширяемый словарь ошибок). UI-область, к которой это применяется: основное приложение (дашборд, «Выбранные», настройки, каналы, обработка) и оператор-консоль (этап 10). ## Открытые точки согласования (накопились к концу этапа 1) > Решения владельца (2026-09-06): 1 — бренд меняем (сделано точечно: index.html, LoginView, Sidebar, DiscoveryView, SettingsView); 2 — инвайты/оператор остаются на SaaS-этап, dev-seed admin/admin; 3 — PascalCase — конвенция БД; 4 — кука `deal_session` остаётся; 5 — заглушки сервисов допустимы (порты с детерминированными локальными реализациями до этапов 6+); 6 — идём по roadmap все этапы. 1. **Бренд во фронте**: Vue-фронт всё ещё показывает «LeadRadar» (LoginView, заголовки). Фронт «не трогаем» — но бренд теперь «Дейл». Менять ли строки бренда во фронте (точечно) или позже? 2. **Инвайты/оператор**: ТЗ требует invite-only + отдельный вход оператора; во фронте такого UI нет. Оставляем dev-seed (admin/admin + дефолтный тенант) до этапа 7? Тогда auth остаётся «как прототип». 3. **Имена колонок БД**: EF генерирует PascalCase (`UpdatedAt`), ТЗ/доки местами в SQL-нотации (snake_case). Оставляем PascalCase (конвенция кода) — подтвердить. 4. **Имя куки** `deal_session` (прототип: `leadradar_session`) — фронту всё равно; ок? 5. **Сервисы ml/ai/telegram**: полный ребилд — это самые крупные этапы. Подтвердить, что локально между этапами допустимы порты с детерминированными заглушками (пока сервисы не написаны), чтобы pipeline/kanban разрабатывать и показывать на синтетических входах. 6. **Приоритет и темп**: продолжать строго по roadmap (Settings → Kanban → Pipeline → Projects → сервисы+Discovery → SaaS-контур) и в каком темпе/объёме на сессию. **Статус на 2026-09-08 (этапы 0–7 завершены):** п.2 **закрыт** — инвайты/оператор реализованы в этапе 7 (API-only: `/api/operator/*` + `/api/join`), dev-seed `admin/admin` остаётся dev-only (Ruling 1); UI операторской админки и страницы активации — задел этапа 8+. п.1 — бренд во фронте меняется точечно (как решено); п.3–5 — зафиксированы решениями (PascalCase, `deal_session`, локальные реализации портов) и не пересматривались; п.6 — roadmap исполнен: этапы 0–7 пройдены (STATUS.md — 100%, Manual-чек-лист вынесен отдельно).