# Spec: Roadmap до production — Лидерра

**Версия:** 1.0
**Дата:** 10.05.2026
**Автор:** Claude Code (skill: superpowers:brainstorming)
**Заказчик:** Дмитрий
**Статус:** черновик, ждёт review заказчика
**Базовый HEAD:** `6c2f0ce` (Sprint 3 Phase C closed)
**Источники:** [docs/audit_2026-05-09.md](../../audit_2026-05-09.md), [docs/Открытые_вопросы_v8_3.md](../../Открытые_вопросы_v8_3.md) v1.76, memory `project_state.md` (вне репо, Claude auto-memory)

## 1. Цель

Довести Лидерру от текущего состояния (Post-MVP, 13/13 экранов handoff покрыты, 416 Pest / 416 Vitest зелёные, MVP-фаза признана закрытой 09.05.2026) **до production-запуска в Yandex Cloud** под доменом `liderra.ru`.

**Pre-condition:** `git push` 18 застрявших коммитов разблокирован (см. §3.0). Без этого CI на GitHub отстаёт от факта на полтора месяца разработки и любая работа в roadmap'е накапливается локально.

**Definition of done «production launch»:**

- Приложение развёрнуто в Yandex Cloud (compute + Managed PG 16 + Managed Redis + Object Storage + Container Registry)
- Домен `liderra.ru` + SSL активны
- SSO `Yandex 360` для saas-admin работает
- Все backend-routes защищены auth/tenant middleware (P1-10/P1-11 закрыты)
- 0 known P0/P1, audit-хвост O-* закрыт или явно отложен с условием снятия
- Phase 3 tooling (#25–29) активен (Semgrep + Trivy + Dependabot + pg_audit + pg_anonymizer)
- Pa11y на live URL = 0 violations
- Sentry self-hosted получает события из prod
- Backup протестирован (restore из snapshot работает)
- Runbook и incident-response готовы
- Smoke-тесты на staging-домене зелёные
- Регрессия зелёная (Pest / Vitest / Larastan / vue-tsc / ESLint / squawk / SAST / Trivy)

## 2. Scope и non-goals

### В scope

- **Категория A:** хвосты audit O-* (~10 пунктов, не вошли в Sprint 1–3)
- **Категория B:** Phase 3 tooling (#25 Semgrep, #26 Trivy, #27 Dependabot, #28 pg_audit, #29 pg_anonymizer)
- **Категория C:** Post-MVP backend backlog (Reports доделки, AdminTenantDetail доделки, Notification integrations)
- **Категория D:** Б-1-зависимые фичи (SSO #6, P1-11 admin auth, лендинг, Диз-3/4, DO-2/4)
- **Категория E:** Production deployment в Yandex Cloud
- **Категория G:** push 18 застрявших коммитов (precondition)

### Не в scope

- **Категория F:** юридические тексты (Прил. Ж оферта + Политика + Прил. З уведомление РКН) — внешний исполнитель (юрист), Claude может только импортировать готовый текст
- 5 🟦 структурных вопросов реестра (Биз-/Ю-/Диз-) — ждут заказчика
- Post-launch фичи (новые модули CRM, аналитика второго порядка, мобильное приложение)
- «Refactor ради рефактора» вне списка O-*

### Допущения

- **Б-1 ETA:** «недели/месяц» (по словам заказчика). План построен **двухдорожечно**, чтобы не зависеть от точной даты — Track A работает параллельно с ожиданием Б-1, Track B стартует по триггеру «реквизиты получены».
- **Native Windows-стенд** остаётся dev-средой до prod-миграции. На нём недоступны Docker, WSL2, Hyper-V, pg_partman, pg_audit, pg_anonymizer, Pest browser-driver (ext-sockets). Все инструменты, требующие Linux-стенда, переносятся на Track B (после получения staging YC).
- **Push разблокирован** (категория G) — без этого Sprint 4 не стартует.

## 3. Архитектура roadmap'а — три дорожки

```
[Sprint 0 / Pre-condition]
    G. push 18 commits → unblock CI
              ↓
              ├─────────── Track A (параллельно ожиданию Б-1) ───────────────┐
              │                                                              │
              │  Sprint 4 «Audit tail»                                       │
              │     A. O-perf-04, O-perf-07, O-refactor-04(хвост), -05,      │
              │        -06, -07, O-stack-02, O-stack-03                      │
              │                                                              │
              │  Sprint 5 «Pre-prod tooling — что возможно без YC»           │
              │     B. #25 Semgrep + Semgrep MCP                             │
              │        #26 Trivy (готовим, активируем после YC)              │
              │        #27 Dependabot (.github/dependabot.yml)               │
              │        (#28/#29 ждут Managed PG)                             │
              │                                                              │
              │  Sprint 6 «Post-MVP backend»                                 │
              │     C. Reports backend доделки (3 providers,                 │
              │        file download, S3 abstraction)                        │
              │        AdminTenantDetail доделки (inn/phone/address,         │
              │        user roles)                                           │
              │        Notification integrations (new_device_login,          │
              │        deep-link bell, ЮKassa webhook scaffold)              │
              │                                                              │
              └──────────────────────────────────────────────────────────────┘
                                      │
                                      ▼ (когда Б-1 закрыт)
              ┌───── Track B (после Б-1) ────────────────────────────────────┐
              │                                                              │
              │  Sprint 7 «YC infrastructure setup»                          │
              │     E. Compute (VM или Managed K8s)                          │
              │        Managed PG 16 (snapshots, replicas, pg_partman)       │
              │        Managed Redis                                         │
              │        Object Storage (S3-compatible) для report files       │
              │        Container Registry (YCR)                              │
              │        Sentry self-hosted (отдельная VM)                     │
              │        Domain liderra.ru + SSL (Let's Encrypt)               │
              │                                                              │
              │  Sprint 8 «CI/CD + Б-1-features»                             │
              │     E. CI/CD pipeline (GitHub Actions → docker → YCR → deploy)│
              │        Secrets (Yandex Lockbox)                              │
              │        Unisender Go SMTP-relay (реальные креды)              │
              │     D. SSO Yandex 360 (#6)                                   │
              │        P1-11: auth-middleware на /api/admin/*                │
              │        Реальный лендинг (DO-2/4 + Диз-3/4)                   │
              │        JivoSite виджет                                       │
              │                                                              │
              │  Sprint 9 «Hardening + soft-launch»                          │
              │     B. #28 pg_audit + #29 pg_anonymizer (на Managed PG)      │
              │        #26 Trivy полный pipeline активирован                 │
              │     E. Backup strategy (snapshots + S3 versioning)           │
              │        Monitoring + alerting (YC Monitoring + Sentry)        │
              │        Runbook (incidents + restore + migrations)            │
              │        Pre-launch security review (Semgrep + Trivy + manual) │
              │        Pa11y на live URL                                     │
              │        Smoke-тесты на staging-домене                         │
              │        Soft-launch (закрытая бета на доверенных tenant'ах)   │
              │                                                              │
              └──────────────────────────────────────────────────────────────┘

              Track C (external — вне Claude):
                F. Юр. тексты (Прил. Ж/З) — нужны для Sprint 8 (лендинг footer)
                Б-1: регистрация ООО — триггер Track B
                5 🟦 структурных вопросов реестра — ждут заказчика
```

### 3.0 Sprint 0 / Pre-condition (категория G)

**Действие заказчика (≈5 минут):**

1. GitHub → Settings → Developer settings → Personal access tokens (fine-grained)
2. Найти токен с доступом к `CoralMinister/lidpotok`
3. Edit → Repository permissions → **Workflows: Read & Write** (отдельная permission, не Contents)
4. Save (новый секрет не выпускается, permission добавляется к существующему)

**Действие Claude:** `git push origin main` после подтверждения от заказчика. 18 коммитов уезжают, GitHub Actions подхватывают.

**Acceptance:** `origin/main == 6c2f0ce`, `git status` clean, GitHub Actions «green» на последнем коммите.

### 3.1 Track A: что не зависит от Б-1 (Sprint 4–6)

| Sprint | Категория | Длительность (агент-часы) | Wall-clock (calendar) | Регрессия после |
|---|---|---|---|---|
| **4** «Audit tail» | A | 8–12 | 1 неделя | Pest зелёный, Vitest +N (на split'ах), Larastan + ESLint + vue-tsc 0 |
| **5** «Pre-prod tooling local» | B (#25/#26-prep/#27) | 6–8 | 0.5 недели | + SAST CI зелёный + Dependabot активен |
| **6** «Post-MVP backend» | C | 12–16 | 1.5 недели | + Pest +30, Vitest +20, новые миграции в schema |

**Sprint 4 содержание (детально, ревизия после audit фактического состояния):**

- O-perf-04: keyset pagination в `DealController::index` по `(received_at, id)` — M
- O-refactor-04 хвост: 8 Vue-компонентов >300 строк (AppLayout 466, AdminTenantDetailView 436, BillingView 416, AdminTenantsView 377, SecurityTab 354, RemindersView 345, ErrorView 320, DashboardView 302) — split на sub-компоненты <200 строк через выделение sections. Группами: 3 admin views (1 коммит), 3 user views (1 коммит), 2 layout/utility (1 коммит). ImpersonationDialog (291) уже <300 — out of scope
- O-refactor-06: `npm run build --analyze` (rollup-plugin-visualizer или vite --analyze) + удаление unused exports в `utils/` и `helpers/` — S+M

**Уже закрыто ранее (исключено из Sprint 4):**

- O-perf-07 — Larastan cache закрыт в Sprint 2 Phase A (`tmpDir: .phpstan-cache` в `phpstan.neon`); pre-push move не нужен при работающем cache
- O-refactor-05 — ESLint `no-restricted-imports` против `vuetify/components` закрыт в Sprint 1 (`eslint.config.js`)
- O-refactor-07 — шапка CLAUDE.md фактически 30 строк до §1 (после `5b13c95` вынос changelog); audit-метрика «244 строки» устарела
- O-stack-02 — `infection/infection ^0.32.7` установлен в Sprint 2 Phase A + `composer mutation` script + `infection.json`
- O-stack-03 — Laravel 13 string-based lazy-loading закрыт в Sprint 2 Phase A (`routes/web.php` все 16 контроллеров на строки `'FQN@method'`)

**Sprint 5 содержание (детально):**

- #25 Semgrep + Semgrep MCP: `.semgrep/` config + `npm run sast` + GitHub Action в `.github/workflows/`
- #26 Trivy: подготовка скрипта `bin/trivy-scan.sh` + GitHub Action stub (активируется в Sprint 9 когда есть Docker-образы)
- #27 Dependabot: `.github/dependabot.yml` с конфигом для composer + npm + github-actions

**Sprint 6 содержание (детально):**

- Reports backend:
  - 3 Provider-классы: `ManagersSummaryProvider`, `SourcesSummaryProvider`, `BillingSummaryProvider` (по analogii с `DealsExportProvider`)
  - `GET /api/reports/jobs/{id}/file` — endpoint скачивания (auth + ownership check + StreamedResponse + Content-Disposition)
  - S3-driver абстракция: `Storage::disk('reports')` с config-driven driver (local на dev, s3 на prod)
- AdminTenantDetail доделки:
  - Schema migration: `tenants` + `inn`, `contact_phone`, `legal_address` или связь на `legal_entities` (брейнсторм отдельно — что лучше)
  - `user_roles` enum-колонка в `users` (или таблица — решить в реализации) + миграция данных (default 'manager'), убрать UI-хардкод
- Notification integrations:
  - `new_device_login`: расширить `user_sessions` на fingerprint (IP + UA hash), trigger при новой комбинации
  - Deep-link bell: `notification.context.deal_id` → `<router-link to="/deals/{id}">` (вместо общего push на `/deals`)
  - ЮKassa webhook scaffold: `POST /webhook/yookassa` контроллер с HMAC + сигнатурой ЮKassa, вызывающий готовый `notifyTopupSuccess`/`notifyInvoicePaid`

### 3.2 Track B: после Б-1 (Sprint 7–9)

**Триггер запуска Track B:** заказчик передаёт реквизиты ООО + DO-2 (`liderra.ru` куплен/перенесён) + Прил. Ж/З получены от юриста.

**Sprint 7 содержание (детально):**

- Yandex Cloud setup:
  - Решение «VM vs Managed K8s» — для MVP-стадии достаточно 2 VM (web + db replica), K8s overkill
  - Managed PostgreSQL 16: 2 ноды (master + sync replica), backup window, pg_partman pre-install, миграция schema.sql v8.11 (через `migrate:fresh` + seed)
  - Managed Redis: cluster mode off, 1 нода + replica для failover
  - Object Storage bucket `liderra-reports` (private), bucket `liderra-static` (public) для будущего
  - Container Registry `cr.yandex/<registry-id>/liderra-app`
  - Sentry self-hosted: отдельная VM, docker-compose, домен `sentry.liderra.ru`
- Domain + SSL:
  - DNS: A-record `liderra.ru` + `*.liderra.ru` → load balancer
  - SSL: Let's Encrypt через certbot (автоматическое продление)

**Sprint 8 содержание (детально):**

- CI/CD:
  - `.github/workflows/deploy.yml`: build PHP-FPM image + nginx image + frontend assets → push в YCR → `ssh deploy@vm` + docker-compose up
  - Secrets: Yandex Lockbox для DB password, ЮKassa keys, Yandex 360 client_secret, Sentry DSN
- Email:
  - Unisender Go: SMTP-relay креды в `.env.production`, тестовая отправка → mail.ru/yandex.ru/gmail.com (3 провайдера)
- Б-1-features:
  - Yandex 360 SSO (#6): OAuth2 client config, `/auth/yandex/callback` route, `saas_admin_users` синхронизация, list разрешённых email из `liderra.ru`-домена
  - P1-11: `Route::middleware(['auth:saas-admin'])` на all `/api/admin/*` — переоткрытие routes без middleware-bypass
  - Лендинг: реализация по `лендинг/TZ_landing_v1_0.md` v1.0 (Vue компоненты или статика — решить отдельно), footer-контакты (Диз-3), контент (Диз-4)
  - JivoSite виджет: snippet в base layout

**Sprint 9 содержание (детально):**

- DB hardening:
  - #28 pg_audit: `CREATE EXTENSION pg_audit;` + конфиг log_catalog/log_level/log_relation
  - #29 pg_anonymizer: маскирование `users.email`, `users.phone`, `deals.lead_phone` в дампах для разработки
- CI/CD finalization:
  - #26 Trivy полный pipeline: scan → fail на CVE high+ → block merge
- Monitoring:
  - Yandex Monitoring: dashboards (CPU, RAM, disk, PG connections, Redis hit-rate)
  - Alerting: PagerDuty или Telegram bot на critical
  - Sentry integration: `sentry/sentry-laravel` + Vue release notify
- Backup strategy:
  - PG snapshots: daily, retention 7 дней
  - Object Storage versioning: enabled на reports + uploads
  - Restore drill: воспроизвести prod-БД в staging из snapshot, проверить целостность
- Security:
  - Pre-launch review: Semgrep + Trivy clean, manual check OWASP top-10
  - Pa11y на live URL (после CDN + font-loading): 0 violations
- Launch:
  - Smoke на staging-домене (`staging.liderra.ru`): 5 ключевых flow (login → создать deal → import webhook → оплатить → отчёт)
  - Soft-launch: 3–5 доверенных tenant'ов на 2 недели, мониторинг ошибок
  - Public launch после 0 P0 за 2 недели soft-launch'а

### 3.3 Track C: external (вне Claude)

| Что | Кто | Когда нужно |
|---|---|---|
| Регистрация ООО → реквизиты | заказчик + юрист | Триггер Track B |
| Прил. Ж: оферта + Политика конфиденциальности | юрист | Sprint 8 (footer лендинга) |
| Прил. З: уведомление в РКН (152-ФЗ) | юрист | Sprint 9 (до запуска) |
| 5 🟦 структурных вопросов реестра | заказчик | по мере появления |

## 4. Зависимости и критический путь

```
G (push) → Sprint 4 → Sprint 5 → Sprint 6 ─┐
                                            ├─→ Sprint 9 → launch
                            Б-1 → Sprint 7 → Sprint 8 ─┘
```

**Критический путь** (longest path):

- Если Б-1 закрывается **раньше** конца Sprint 6: критический путь = G → 4 → 5 → 6 → 9 (Sprint 7+8 параллельно с 5+6, насколько позволят руки)
- Если Б-1 закрывается **позже** конца Sprint 6: критический путь = G → Б-1 → 7 → 8 → 9, Sprint 4–6 уже закрыты

**Жёсткие зависимости:**

- Sprint 7 ⇐ Б-1 (нельзя купить compute от ООО без ООО)
- Sprint 9 ⇐ Sprint 7 (pg_audit/pg_anonymizer только на Managed PG)
- Sprint 9 ⇐ Прил. Ж + Прил. З (нельзя запустить без РКН-уведомления и оферты)
- Sprint 8 ⇐ Прил. Ж (footer лендинга нужен оферту)

**Мягкие зависимости (можно параллелить):**

- Sprint 5 || Sprint 4 (разные подсистемы)
- Sprint 6 после Sprint 5 (полезно иметь Semgrep clean перед расширением API)

## 5. Метрики и acceptance

### Per-sprint exit criteria

| Sprint | Acceptance |
|---|---|
| 0 | `git push` зелёный, GitHub Actions зелёные на 6c2f0ce, `git status` clean |
| 4 | Pest +0 / Vitest +N (split'ы добавили tests на новые компоненты) / Larastan + ESLint + vue-tsc 0 ошибок / 0 Vue-компонентов >300 строк (либо ≤2 с обоснованием) |
| 5 | Semgrep CI зелёный, 0 high-severity findings; Dependabot создал хотя бы 1 PR на тестовом обновлении; Trivy script готов к активации |
| 6 | 3 Provider-класса покрыты Pest-тестами; file-download endpoint работает; AdminTenantDetail все поля без хардкода; ЮKassa webhook принимает signed payload |
| 7 | `pg_isready` на Managed PG OK; Redis ping OK; `liderra.ru` резолвится; SSL валиден; Sentry принимает test event |
| 8 | CI deploy на staging проходит; SSO admin-login работает; `/api/admin/*` без auth = 401; лендинг доступен по `liderra.ru/`; 3 провайдера почты получили test mail |
| 9 | pg_audit логи пишутся; Trivy в pipeline блокирует CVE high+; backup restore проверен; Pa11y 0 violations на live; soft-launch tenant'ы залогинились |
| **launch** | Все § 1 «Definition of done» закрыты + 14 дней soft-launch без P0 |

### Регрессия каждого Sprint'а

```bash
composer test          # Pest
composer stan          # Larastan 0
composer pint          # без diff
npm run test:vue       # Vitest
npm run lint:vue       # ESLint 0
npm run type-check     # vue-tsc 0
npm run check:docs     # markdownlint + cspell + lychee + pa11y
npm run sast           # Semgrep (с Sprint 5)
```

## 6. Риски и mitigations

| Риск | Вероятность | Impact | Mitigation |
|---|---|---|---|
| Б-1 затягивается на 2+ месяца | средняя | блокирует Track B | Track A автономен на 3 спринта; после исчерпания — заказчик решает: ждать / перейти на ИП / прод-стенд под физлицом |
| Push-blocker (Workflows R&W) не разрешён | низкая | блокирует ВСЁ | заказчик уже в курсе, действие 5 минут |
| Histoire ↔ Vite 8 несовместимость не разрешится | низкая | низкое | продолжаем `--legacy-peer-deps` workaround; после Vite 9 решать заново |
| Pest 4 browser-tests blocked on Windows | высокая | низкое | Playwright взамен (Sprint 5 опционально), full Pest browser — на Linux staging Sprint 7+ |
| Yandex Cloud quota / новый аккаунт verification долгий | средняя | удлиняет Sprint 7 | заявка на quota подаётся как только Б-1 закрыт, parallel со Sprint 6 |
| Юрист задерживает Прил. Ж/З | средняя | блокирует Sprint 8/9 | заказчик ставит юристу deadline под Sprint 7 закрытие |
| Managed PG миграция данных (если уже есть тестовые) | низкая | средний | на момент миграции data prod = пусто, dev-data выкидываем |
| Pre-launch security review находит P0 | средняя | удлиняет Sprint 9 | Semgrep + Trivy в Sprint 5/9 заранее ловят 80% |
| Soft-launch выявит UX-проблему | высокая | средний | плановое: 2 недели запас, ловим итеративно |

## 7. Open questions для будущей детализации

Эти вопросы решатся в момент написания implementation plan'а каждого Sprint'а — не блокируют design этого roadmap'а:

- **Sprint 6:** `tenants.inn/phone/address` — колонки или JOIN на `legal_entities`? Зависит от того, есть ли отдельный flow «тенант — юр. лицо» (M-вопрос)
- **Sprint 6:** `users.role` — enum-колонка или таблица `user_roles`? Если только 1 роль на user — enum проще; если несколько — таблица. Нужно уточнить product requirement
- **Sprint 7:** VM vs Managed K8s — для MVP-нагрузки (≤100 tenant'ов, ≤10K leads/day) хватит 2 VM. K8s overkill, отложить до post-launch масштабирования
- **Sprint 9:** какой alerting-канал — Telegram bot, PagerDuty, email? Дешёвый default — Telegram bot
- **Sprint 9:** soft-launch tenants — кто они? Заказчик подбирает 3–5 проверенных компаний

## 8. История версий

- **v1.0 от 10.05.2026** — первичный roadmap, двухдорожечная структура (Track A не блокировано Б-1, Track B после Б-1, Track C external). 9 sprint'ов всего (Sprint 0 + 4–9). Базовый HEAD `6c2f0ce`.
