Дмитрий
280cfcd6cf
feat(routes): register POST /api/webhook/supplier/{secret}
...
Spec §5.1 supplier-webhook endpoint. SupplierWebhookController tests
переходят с 405 на 8/8 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 19:39:43 +03:00
Дмитрий
e41c8f5aef
feat(http): SupplierWebhookController — platform-wide /api/webhook/supplier/{secret}
...
Defense-in-depth: secret (≥32 chars system_setting) + IP allowlist (CIDR).
Несовпадение → 404. UNIQUE vid → 200 OK на дубль (idempotency).
Тесты пока FAIL (route регистрируется в Task 7 — пишем "красные" тесты заранее
для TDD-цикла).
Spec §5.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 19:38:18 +03:00
Дмитрий
605c457c49
fix(jobs): RouteSupplierLeadJob — per-Project failure isolation + 2 tests
...
Code-review Important: один сбой Project не должен абортить routing для
остальных tenant'ов (sharing-model). + try/catch + Log::warning +
RuntimeException только если ВСЕ projects упали.
+ 2 новых теста: mixed routing (1 dup из 3 + 2 clean) и partial failure
(soft-delete tenant в середине loop'а).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 19:30:06 +03:00
Дмитрий
c519044319
feat(jobs): RouteSupplierLeadJob — sharing-model deal-copies + charge per tenant
...
Распределяет supplier_lead по eligible Liderra-проектам через LeadRouter.
Для каждого: транзакция с SET LOCAL app.current_tenant_id, lockForUpdate,
DuplicateDetector check, balance_leads--, delivered_today/month++,
BalanceTransaction, ActivityLog, NotificationService::notifyNewLead.
Spec §5-§6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 19:05:21 +03:00
Дмитрий
9540090bba
fix(services): LeadRouter — Europe/Moscow timezone for workday-mask check
...
Code-review Important: Carbon::now() resolved against process TZ (UTC quirk
из memory). Reset cron в 00:00 МСК — mismatch вызвал бы off-by-one на
рубеже полуночи. Тест синхронизирован (now('Europe/Moscow')) — иначе
mismatch test/service near midnight. + комментарий про unreachable default
match arm (защищён на DB-уровне через chk_supplier_projects_platform).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:56:15 +03:00
Дмитрий
31929c9dd2
feat(services): LeadRouter — eligible Liderra projects matcher
...
Plan 2/5 Task 4 — sharing-model routing (spec §6): для входящего лида
возвращает Collection<Project> учитывая platform FK + active + workdays +
region (PhonePrefixService::phoneMatchesRegions) + delivered_today <
COALESCE(effective_daily_limit_today, daily_limit_target) +
tenant.balance_leads > 0. Сортировка created_at ASC, id ASC (детерминированно).
Параллельно расширил Project model fillable/casts на delivered_today
(колонка добавлена в schema v8.18 Plan 2 Task 1, но Project::class не
обновлён — без этого тесты Mass-Assignment'а ломались).
Покрытие: 9 it-blocks (sharing across tenants, paused, workdays, daily quota,
fallback to daily_limit_target, region filter, balance_leads zero, FK routing
по platform, deterministic sort). DatabaseTransactions context + set_config
(session-scoped) для очистки app.current_tenant_id — sharing-flow работает
поверх N tenant'ов, RLS bypass через postgres BYPASSRLS на dev.
PHPStan: 0 errors. Pint: clean. Pest: 9/9 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:50:28 +03:00
Дмитрий
5f08459615
feat(services): PhonePrefixService — phone → federal district bit (MVP)
...
Маппинг мобильных + 30+ ABC-кодов городов на 8 ФО RF (synchronized
с projects.region_mask битами). Мобильные → all-districts (255).
Полный Минсвязи справочник отложен на Plan 5+.
Spec: §6 step 2 routing geo-filter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:36:43 +03:00
Дмитрий
aa37f4cbed
feat(models): SupplierLead model + factory (raw-payload incoming webhooks)
...
SaaS-level модель для supplier_leads (Plan 2/5 Task 2).
belongsTo(SupplierProject) + array cast на raw_payload + datetime *_at.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:24:45 +03:00
Дмитрий
f5c7c29301
test(schema): add UNIQUE-vid behavioral test + intent-clear placeholder assert
...
- Add it-block для UNIQUE INDEX idx_supplier_leads_vid_unique:
две INSERT с одинаковым vid → вторая бросает QueryException
(прямой behavioral тест webhook-идемпотентности).
- Replace tautological strlen($secret->value) >= 16 на toBe('__SET_ON_DEPLOY__')
— было проверкой литерала, который мы сами и записали; теперь intent-clear
assertion того, что seed кладёт placeholder. Реальная strength-валидация
secret'а — дело deploy-time validator'а, вне scope Plan 2.
- Add uses(DatabaseTransactions::class) — приводит файл к проектному
pattern (см. WebhookReceiveTest, TenantModelsTest, SetTenantContextTest).
Без него новый INSERT с vid=999000111 коллидил бы при re-run, т.к.
Pest.php применяет RefreshDatabase глобально не делает (закомментирован).
Code-review fixes for Plan 2 Task 1.
2026-05-10 18:16:19 +03:00
Дмитрий
fb55bfdd1f
feat(db): supplier_leads + projects.delivered_today + 2 system_settings (v8.18)
...
Plan 2/5 Task 1 — слой данных для supplier-webhook flow.
- supplier_leads (SaaS-level, без RLS) — raw payload incoming webhook'ов
- projects.delivered_today — дневной счётчик для проверки daily quota
- system_settings: supplier_webhook_secret + supplier_ip_allowlist
Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §5-§6
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 18:07:31 +03:00
Дмитрий
00aaa9ea89
docs(plan): Plan 2/5 — Supplier Webhook + Sharing Routing
...
11 задач + 14-пунктовый Comprehensive Verification Gate.
Spec §5-§6: platform-wide webhook + N deal-копий через LeadRouter.
Legacy /api/webhook/{token} остаётся параллельным каналом.
+ allowlist generic pattern 7\d{3}1234567 для PhonePrefixService docs/tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 17:55:13 +03:00
Дмитрий
001d7819bf
fix(supplier): close code-review BLOCKER+WARN — FK + CHECK + resolver guard
...
Code-review subagent (CV.12 в Plan 1) нашёл 1 BLOCKER + 2 actionable WARNINGs:
1. **BLOCKER** — projects.supplier_b{1,2,3}_project_id были голыми BIGINT без
REFERENCES, вопреки явному комментарию «FK добавятся в Task 2». Task 2
создал supplier_projects, но FK на projects не вернул. Можно было записать
произвольный BIGINT в эти колонки.
Fix: ALTER TABLE projects ADD CONSTRAINT … FOREIGN KEY … ON DELETE SET NULL
для всех трёх + 3 partial index (WHERE NOT NULL) для FK lookup.
2. **WARNING** (Project-level B1+SMS guard) — CHECK существовал только на
supplier_projects; Project::create(['signal_type'=>'sms','supplier_b1_project_id'=>…])
проходил вопреки spec §2.2 «B1 не поддерживает СМС».
Fix: ADD CONSTRAINT chk_projects_b1_not_for_sms
CHECK (signal_type <> 'sms' OR supplier_b1_project_id IS NULL).
3. **WARNING** (resolver collision) — SupplierProjectResolver::resolveOrStub
firstOrCreate на (platform, unique_key) без signal_type → при коллизии
unique_key возвращал чужую запись с другим signal_type без ошибки.
Fix: после firstOrCreate проверяется match signal_type, иначе DomainException.
+1 тест на collision.
Schema bumped v8.16 → v8.17. Метрики: 60 таблиц / 111 индексов (+3) / 39 RLS.
Pest: 500/498 passed (+1 collision test). Larastan 0 errors. Pint clean.
Spec: §2.1, §2.2
Plan: Task 2 (закрытие code-review CV.12)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 17:32:02 +03:00
Дмитрий
44a1b21421
feat(rules): add Signal validators (Domain, Phone, SmsSender) with comprehensive datasets
...
- app/Rules/SignalIdentifier/DomainIdentifier.php — regex
^[a-z0-9-]+(\.[a-z0-9-]+)+$ (нижний регистр, без протокола/пути).
- app/Rules/SignalIdentifier/PhoneIdentifier.php — regex ^7\d{10}$
(11 цифр, начинается с 7).
- app/Rules/SignalIdentifier/SmsSenderRule.php — 1-30 символов
[A-Za-z0-9_-]; отвергает 11-значные номера (поставщик блокирует
физический телефон в роли отправителя — alert "Важно!" в форме
создания SMS-проекта).
- tests/Feature/Rules/SignalValidatorsTest.php — 24 теста с datasets:
• Domain: 4 valid + 6 invalid (case, no-TLD, spaces, protocol, path, double-dot)
• Phone: 3 valid + 6 invalid (8-prefix, length, plus, spaces, letters)
• SmsSender: alpha+numeric short, 11-digit blocked, length>30 blocked,
empty (с required), special chars blocked
Quirk: Laravel skips non-implicit rules для пустых строк. Тест empty
использует связку 'required' + правило (как в реальном FormRequest).
Pest: 499 / 497 passed / 2 skipped (473 + 24 новых = 497).
Larastan: 0 errors. Pint passed.
Spec: §3.1
Plan: Task 12
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 17:05:19 +03:00
Дмитрий
59c57f9ec0
feat(services): add SupplierProjectResolver (resolveOrStub with B1+SMS guard)
...
- app/Services/SupplierProjects/SupplierProjectResolver.php — резолвер
по ключу (platform, signal_type, unique_key). Возвращает existing supplier_project
или создаёт pending stub (физическая sync произойдёт в SyncSupplierProjectsJob, Plan 3).
- Защита 1: InvalidArgumentException на платформу не из {B1,B2,B3}.
- Защита 2: InvalidArgumentException на signal_type не из {site,call,sms}.
- Защита 3: DomainException на B1+SMS combo (chk_supplier_projects_b1_not_for_sms).
- tests/Feature/Services/SupplierProjectResolverTest.php — 6 тестов:
resolve existing, create stub, idempotency (no duplicates), B1+SMS guard,
invalid platform, invalid signal_type.
Pest: 475 / 473 passed / 2 skipped (467 + 6 новых = 473).
Larastan: 0 errors. Pint passed.
Spec: §2.2, §4.1
Plan: Task 11
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 17:02:25 +03:00
Дмитрий
99afcbc25c
feat(models): extend Project with signal_type, sms_senders, supplier_b1/b2/b3 relations + scopes
...
- app/Models/Project.php — добавлены fillable+casts для supplier integration:
signal_type, signal_identifier, sms_senders (jsonb array), sms_keyword,
delivered_in_month, supplier_b{1,2,3}_project_id.
+ supplierB1/B2/B3() BelongsTo relations на SupplierProject (sharing-model).
+ scopeActiveOnDay($iso) — bitmask проверка по delivery_days_mask
(bit 0 = Mon, bit 6 = Sun; ISO=1 → 1<<0 = 1; ISO=7 → 1<<6 = 64).
+ scopeForSignal($type, $identifier) — фильтр по сигналу (для роутинга в Plan 2).
- database/factories/ProjectFactory.php — defaults null/0 для новых полей
(CHECK constraints не нарушаются: signal_type IS NULL → остальные опциональны).
+ state-методы asSiteSignal($domain), asCallSignal($phone), asSmsSignal($senders, $keyword).
- tests/Feature/Models/ProjectExtensionsTest.php — 6 тестов: signal_type fillable,
sms_senders array cast + sms_keyword, SMS без keyword, supplierB1/B2/B3 relations,
scopeActiveOnDay (bitmask Mon/Sat), scopeForSignal (3 сигнала + edge-case).
Pest: 469 / 467 passed / 2 skipped (461 + 6 новых = 467, с retry на transient
PG connection issues — на параллельных тестах с testing_rls_user GRANT тяжёл).
Larastan: 0 errors. Pint passed.
Spec: §2.1
Plan: Task 10
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:59:53 +03:00
Дмитрий
084a952bfa
feat(models): add SupplierSyncLog model + factory (audit trail для AJAX-sync)
...
- app/Models/SupplierSyncLog.php — fillable + casts (jsonb arrays + datetime)
+ supplierProject() BelongsTo relation (nullable, ON DELETE SET NULL —
лог переживает удаление supplier-проекта для audit-trail).
$timestamps = false (только created_at, без updated_at — append-only)
- database/factories/SupplierSyncLogFactory.php — реалистичные действия из enum
- tests/Feature/Models/SupplierSyncLogTest.php — 4 теста: factory,
supplier_project relation, jsonb array casts, nullable FK lifecycle
Pest: 463 / 461 passed / 2 skipped (457 + 4 новых = 461).
Larastan: 0 errors. Pint passed.
Spec: §4.3
Plan: Task 9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:53:55 +03:00
Дмитрий
31f813315d
feat(models): add LeadCharge ledger model + factory + relations to Tenant/Deal
...
- app/Models/LeadCharge.php — fillable + casts (datetime + integer)
+ tenant() BelongsTo relation
+ deal() BelongsTo relation (по deal_id, без deal_received_at — composite PK
на партиционированной обеспечивается БД-уровнем через FK)
+ accessor priceRubles (kopecks → float)
- database/factories/LeadChargeFactory.php — НЕ создаёт реальный Deal автоматически
(composite FK requires (deal_id, deal_received_at) пары); тесты с FK-целостностью
явно создают Deal::factory() и передают пару в state()
- tests/Feature/Models/LeadChargeTest.php — 4 теста: factory, tenant relation,
deal relation, priceRubles accessor. testing_rls_user setup в beforeEach
для проверки RLS context из не-superuser контекста.
Quirk: SET LOCAL app.current_tenant_id НЕ принимает параметрическое связывание PG —
используем string interpolation с {$tenant->id} как в RlsSmokeTest pattern.
ide-helper:models -W -M -N синхронизировал docblocks (WebhookDedupKey).
Pest: 459 / 457 passed / 2 skipped (453 + 4 новых = 457).
Larastan: 0 errors. Pint passed.
Spec: §7.4
Plan: Task 8
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:52:10 +03:00
Дмитрий
71e38ee0a9
feat(models): add PricingTier model with kopecks→rubles accessor + current() snapshot
...
- app/Models/PricingTier.php — fillable + casts (date, boolean, integer)
+ accessor priceRubles (kopecks → float rubles)
+ scopeActive (is_active=true AND effective_from <= today)
+ static current() — keyed by tier_no Collection<int, PricingTier>
- database/factories/PricingTierFactory.php — реалистичные ступени (300/700/1000/.../null)
- tests/Feature/Models/PricingTierTest.php — 4 теста: factory, accessor,
scopeActive, current() snapshot всех 7 ступеней
ide-helper:models -W -M -N перегенерил docblocks (WebhookDedupKey synced
после schema v8.16).
Pest: 455 / 453 passed / 2 skipped (449 + 4 новых = 453).
Larastan: 0 errors. Pint auto-fix.
Spec: §7.2
Plan: Task 7
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 16:48:00 +03:00
Дмитрий
62aa55f033
feat(models): add SupplierProject Eloquent model + factory + tests
...
- app/Models/SupplierProject.php — fillable + casts (jsonb arrays + datetime)
+ scopes: active() (inactive_since IS NULL), staleSince(N days),
forSignal(signal_type, unique_key)
- database/factories/SupplierProjectFactory.php — корректно учитывает
chk_supplier_projects_b1_not_for_sms (B1 не порождает SMS-проекты)
- tests/Feature/Models/SupplierProjectTest.php — 6 тестов: factory,
array casts (workdays + regions), scopeActive, scopeStaleSince,
scopeForSignal (3 платформы на один домен — UNIQUE (platform,unique_key))
ide-helper:models -W -M -N перегенерил docblocks для 4 существующих моделей
(SaasAdminAuditLog, SystemSetting, UserRecoveryCode, ImpersonationToken) —
синхронизировал @property после schema v8.16.
Pest: 451 / 449 passed / 2 skipped (было 443+6 новых от Task 6 = 449).
Larastan: 0 errors. Pint: passed.
Spec: §2.2
Plan: Task 6
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 13:59:39 +03:00
Дмитрий
757f963929
fix(db): consolidate Plan 1 Tasks 1-5 into schema.sql (project convention)
...
Project convention использует schema.sql как single source of truth + один
load_initial_schema migration вместо incremental migrations. Мои 5 incremental
миграций конфликтовали с migrate:fresh: load_initial_schema применял
обновлённый schema.sql v8.16, а потом 000001-000005 пытались добавить уже
существующие колонки/таблицы (`signal_type already exists`).
Изменения:
- Удалены 5 incremental миграций 2026_05_10_00000{1..5}_*.
Все DDL уже в schema.sql (v8.11 → v8.16, 4 commits 2ebe000/9b99d81/
b08e1ed/7f694f7/9cf380f).
- В schema.sql lead_charges FK на partitioned deals(id, received_at)
вынесен в самый конец файла (после section 5 с deals), DEFERRABLE
INITIALLY DEFERRED. Иначе DB::unprepared() выдаёт "deals не существует"
на load.
- Тесты в tests/Feature/Integration/ остаются — они проверяют
структурные свойства (column existence, constraint name, RLS via
pg_class) через information_schema, не зависят от того как именно
schema создалась.
Verification:
- migrate:fresh OK на обеих БД (liderra + liderra_testing)
- Pest: 445 tests / 443 passed / 2 skipped / 0 failed
(было 421 baseline + 24 новых для Tasks 1-5 = 443; +2 skipped browser tests)
- Larastan: 0 errors
- Pint: passed
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 13:50:39 +03:00
Дмитрий
9cf380f170
feat(db): create supplier_sync_log audit table (SaaS-level, append-only)
...
Append-only journal AJAX-синхронизаций с поставщиком crm.bp-gr.ru.
Используется для retry, отладки rt-project-* и алертов менеджеру.
- 9 columns: id, supplier_project_id (nullable FK SET NULL),
action, request_payload (jsonb), response_body (jsonb),
http_status, error_message, duration_ms, created_at
- 1 CHECK chk_supplier_sync_log_action
(create/update/delete/disable/session_refresh)
- 3 индекса: supplier_project_id, action, created_at
- REVOKE ALL FROM crm_app_user (DO $$ conditional)
- No RLS (SaaS-level)
Spec: §4.3
Plan: Task 5
Test: 4/4 passed (table, action enum, FK, no RLS).
Schema v8.15 → v8.16. Метрики: 60 таблиц (+1) / 108 индексов (+3).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 13:42:46 +03:00
Дмитрий
7f694f78e0
feat(db): create lead_charges ledger (tenant-scoped RLS, FK to partitioned deals)
...
Append-only ledger списаний за каждый доставленный лид. Tenant-scoped
с RLS tenant_isolation (ENABLE + FORCE + USING/WITH CHECK).
- 8 columns: id, tenant_id, deal_id, deal_received_at, tier_no,
price_per_lead_kopecks, charged_at, created_at
- Composite FK lead_charges_deals_fk(deal_id, deal_received_at) →
deals(id, received_at) DEFERRABLE INITIALLY DEFERRED
(deals партиционирована — DEFERRABLE для атомарного deal+charge)
- 2 индекса: (tenant_id, charged_at), (deal_id, deal_received_at)
- RLS на (tenant_id = current_setting('app.current_tenant_id')::bigint)
- GRANT SELECT, INSERT для crm_app_user (без UPDATE/DELETE — append-only)
Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §7.4
Plan: docs/superpowers/plans/2026-05-10-supplier-foundation-plan.md Task 4
Test: 3/3 passed (table exists, composite FK to deals, RLS enforces
tenant isolation via testing_rls_user role).
Schema v8.14 → v8.15. Метрики: 59 таблиц (+1) / 105 индексов (+2) /
39 RLS (+1) / функции/триггеры без изменений.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 13:38:17 +03:00
Дмитрий
b08e1edb33
feat(db): create pricing_tiers table (7-step volume billing, kopecks integer)
2026-05-10 12:54:02 +03:00
Дмитрий
9b99d81deb
feat(db): create supplier_projects table (SaaS-level aggregate, B1/B2/B3 platforms)
...
Plan 1/5 Task 2 — SaaS-level агрегатная сущность для проектов у поставщиков.
Несколько Лидерра-tenant'ов могут шарить один supplier_project (sharing-model
spec §2.3): для site/call — по domain/phone; для sms — по (sender, keyword)
на B2 или (sender) на B3. RLS НЕ применяется (таблица не tenant-scoped),
defense-in-depth через REVOKE ALL FROM crm_app_user.
Колонки: platform, signal_type, unique_key (TEXT), supplier_external_id,
current_limit, current_workdays/regions (jsonb), sync_status (pending/ok/failed),
last_synced_at, inactive_since (TTL 180 дней), timestamps.
CHECK constraints (chk_supplier_projects_*):
- platform IN (B1, B2, B3)
- signal_type IN (site, call, sms)
- sync_status IN (pending, ok, failed)
- NOT (platform=B1 AND signal_type=sms) — B1 не поддерживает СМС
Indexes: UNIQUE(platform, unique_key); btree на sync_status, inactive_since.
Тесты: 6/6 (table+columns / unique / platform CHECK / sync_status CHECK / no RLS / no privileges).
Schema: v8.12 → v8.13. Метрики: 56→57 таблиц / 98→101 индексов; RLS/функции/триггеры без изменений.
2026-05-10 12:47:25 +03:00
Дмитрий
2ebe000271
feat(db): extend projects for supplier integration (signal_type, identifier, sms_senders, sms_keyword, delivered_in_month, b1/b2/b3 FK placeholders)
...
Plan 1/5 Task 1. Adds 8 columns + 3 CHECK constraints + 1 composite index
to projects table for supplier integration foundation. Schema bumped
v8.11 to v8.12. Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §2.1.
7/7 Pest tests pass; rollback verified.
2026-05-10 12:40:02 +03:00
Дмитрий
7ab7cf51cb
docs(plans): supplier integration plan 1/5 — Foundation (schema + models + validators)
...
12 tasks + 3 verification gates covering:
- 5 migrations: extend projects, supplier_projects, pricing_tiers, lead_charges, supplier_sync_log
- 4 new Eloquent models + factories + Pest unit tests
- Project model extension with signal_type/sms_*/supplier_b1/b2/b3 relations
- 3 signal validators (Domain, Phone, SmsSender) with edge-case datasets
- SupplierProjectResolver service with B1+SMS guard
- Comprehensive verification gate: Larastan + squawk + pgFormatter + cspell + markdownlint + cycle-check + code-review subagent
Spec: docs/superpowers/specs/2026-05-10-supplier-integration-design.md §2, §7
cspell-words: +vashinvestor
.gitleaks.toml allowlist: +test phones for validator datasets
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 12:10:04 +03:00
Дмитрий
3f463f48ea
docs(specs): close all 7 open questions in supplier integration design
...
Q1 SMS validation: B2 = (sender, keyword), B3 = sender only; B1 not available
Q2 Supplier pricing: фиксированная цена за лид
Q3 Liderra billing: 7-tier volume pricing, monthly reset (config in admin)
Q4 Geo filter: MVP, union at supplier + filter on our side
Q5 Webhook auth: defense-in-depth (IP allowlist + secret token in URL)
Q6 Cookie/CSRF refresh: hourly headless Playwright cron + reactive on 401/403
Q7 supplier_project TTL: immediate disable, delete after 180 days no activity
cspell-words.txt: +геофильтр, логинится, encrypter, PHPSESSID
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 11:39:29 +03:00
Дмитрий
ac09603181
docs(specs): supplier integration design (Лидерра ↔ crm.bp-gr.ru)
...
Captures brainstorming output for two-way integration:
- Sharing model: один supplier-лид → много deal-копий клиентам Лидерры
- 3 supplier-проекта на источник (B1/B2/B3), shared между клиентами
- Dynamic limit adjustment через 20:30 МСК cron + AJAX rt-project-update
- Quota distribution Total/3 с приоритетом B1→B2 на остатке
- Instant FIFO routing по дате создания проекта клиента
- Резервирование обоих направлений: pending-changes queue + CSV reconciliation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 11:02:19 +03:00
Дмитрий
528fe16166
docs(plans): Sprint 6 Phase A — Reports backend implementation plan
...
6 tasks: 3 providers (managers/sources/billing) + registry extension +
S3 disk abstraction + file download endpoint. TDD with Pest 4.
Corrects schema column names vs spec (manager_id, type, balance_rub_after)
and uses May 2026 test dates (partitions start 2026-05-01).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-10 09:38:43 +03:00
Дмитрий
2a6f0289db
docs(spec): Sprint 6 Post-MVP backend design (Reports + Notifications + AdminTenantDetail)
2026-05-10 09:13:45 +03:00
Дмитрий
e5848bddec
feat(tooling): Trivy CI workflow prep — disabled until YC Docker ( #26 )
2026-05-10 08:45:17 +03:00
Дмитрий
7123123b48
chore(claude): allow npm run sast in settings.json ( #25 )
2026-05-10 08:43:52 +03:00
Дмитрий
40125ba5a5
feat(tooling): Semgrep MCP server in .mcp.json ( #25 )
2026-05-10 08:42:25 +03:00
Дмитрий
53fb1ec27e
feat(ci): Semgrep SAST workflow — push/PR to main ( #25 )
2026-05-10 08:40:52 +03:00
Дмитрий
5983cc17e3
feat(tooling): Semgrep config + npm run sast script ( #25 )
2026-05-10 08:39:34 +03:00
Дмитрий
3112584ab8
chore(deps): add Dependabot config — npm×2 + composer weekly ( #27 )
2026-05-10 08:36:36 +03:00
Дмитрий
3c13cc5d64
docs(rules): третий аудит нормативки — закрытие 13 находок (CLAUDE.md v1.86 + PSR_v1 v1.7 + Tooling v1.15)
...
P0 (4) — арифметические конфликты в CLAUDE.md, прошли мимо второго аудита:
- §3 header «Карта 28 инструментов» → «33» (header застрял с pre-FD эпохи)
- §3.4 header «(+5, итого 28)» → «итого 29» (после #30 в фазу 2)
- §3.3 footer «из 30 номеров минус #1 = 29» → «33 номеров: 29 phase-active + 3 off-phase + 1 historic»
- §6 «Активно: 19 инструментов из 29» (vs раскладка 9+8+7=24) → «24» в обоих местах
P1 (5) — sync stale `+`-refs после второго аудита:
- PSR_v1 шапка: «CLAUDE.md v1.84+/Pravila v1.9+» → «v1.86+/v1.10+»
- Tooling шапка: «Pravila v1.9+/PSR_v1 v1.5+/CLAUDE.md v1.84+» → «v1.10+/v1.7+/v1.86+»
- CLAUDE.md §5 п.5 «PSR_v1 v1.5+» → «v1.7+»
P2 (2) — внутренние несогласованности:
- PSR_v1 line 4/856 «slot уровня 2.5» → «уровня 2b» (описка внутри changelog'а v1.6)
- CLAUDE.md §3.3 #33 «вне Pravila §13» → «вне UI-пула §13» (Pravila §13.2 v1.10 включает claude-md-management как infrastructure subsection)
Sync-правки в connected files:
- README.md + README_АРХИВ_v8_5.md «карта 28 инструментов» → «33»
- Tooling §11.5/§12 «не входят в 28 инструментов» → «33 формализованные позиции»
Через `/claude-md-management:claude-md-improver` с cross-impact-анализом перед каждой группой правок. Pravila v1.10 без изменений (cross-refs к нему уже актуальны).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 06:32:17 +03:00
Дмитрий
07ed3f1be6
docs(rules): второй аудит нормативки — закрытие 15 находок (CLAUDE.md v1.85 + Pravila v1.10 + PSR_v1 v1.6 + Tooling v1.14)
...
Закрыто 15 находок второго аудита правил использования плагинов и скилов
(4 P0 реальных противоречий + 7 P1 stale-refs + 4 P2 структурных).
Через `/claude-md-management:claude-md-improver`.
P0 — реальные противоречия:
- Tooling §10.3 шаг 2: «3 skills» → «14, все запреты сняты Pravila §11»
(закрыта внутри-документная контрадикция с §4.1 того же файла)
- CLAUDE.md §6: арифметика «33» исправлена (+1 заменённый PG MCP
исторически; раньше 19/29 + 3 = 32, не 33)
- Pravila §13.2: «v1.4 (15 правил)» → «v1.6 (16 правил R0–R15)»
- Tooling §13: добавлены v1.13 + v1.14 entries (раньше история
обрывалась на v1.12, хотя шапка описывала v1.13)
P1 — массовый stale-refs дрейф v1.4→v1.6 + v1.12→v1.14:
- CLAUDE.md §0 cross-refs (Pravila/PSR_v1/Tooling rows), §3.3 #31 , #32 , §5 п.12
- Pravila §11.5 («10 правил»→«16»), §13.9, §13.10
- Tooling §4.4 («10 правил»→«16»), §4.5, §4.6, §4.7
P2 — структурные:
- Tooling Прил. Н добавлен explicit-слотом уровня 2b в priority chain
(CLAUDE.md §1, PSR_v1 R0.1 таблица, Tooling §7) — раньше формальная
дыра «PSR_v1 R0.1 говорит stack ниже Tooling, но Tooling нет ни
в одной priority chain»
- PSR_v1 R0.4.A свёрнут до cross-ref на Pravila §12.3 SoT — устранён
риск дрейфа формулировок (раньше параллелил список разной формулировкой)
- Pravila §0 +note про §11 локальное override-исключение над §2.2/§4.5/§8.4
(раньше §11 формально стоял ниже §9 в цепочке вопреки фактическому
override §2.2/§4.5/§8.4 при skill-инвокации)
- PSR_v1 R0.6 hard-стопы пронумерованы 1–11 для надёжности cross-refs
«пункт 9/10/11» (раньше буллет-list, ссылки молча ломались)
Все 4 файла нормативной документации внутренне непротиворечивы.
История версий синхронизирована.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 05:56:43 +03:00
Дмитрий
ffe34e1b17
docs(registry): Sprint 4 «Audit tail» closure record (v1.76→v1.77)
...
Sprint 4 закрыл 3 оставшихся audit O-* пункта (5 коммитов f77c91d..b912724):
- O-perf-04: keyset pagination в DealController::index + 3 Pest-теста
- O-refactor-04 хвост: 8 Vue-компонентов >300 строк разделены (AppLayout
R0.6 hard-стоп снят явным запросом заказчика)
- O-refactor-06: rollup-plugin-visualizer + knip + cleanup ~165 строк
dead-code в composables/
Acceptance закрыт за исключением 2 known DealsView/DealDetailDrawer
(intentional Sprint 3 defineExpose-контракт).
Регрессия: Pest 421 / Vitest 416 / Larastan 0 / vue-tsc 0 / ESLint 0 / build OK.
Sprint 0 push выполнен (4f36bd3..8c6374d, 21 коммит). PAT Workflows R&W
подтверждена через API-диагностику.
CLAUDE.md/Pravila/Tooling/Plugin_stack_rules — параллельно обновляются
другой сессией (PSR_v1 v1.4 формализация UPM/21st/R15 motion в локальных
коммитах 833e3e6 + cf1aabb ), не трогаю в этом коммите.
cspell-words: +oxc (oxc-parser Windows quirk knip), +консты (Russian slang).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 05:06:47 +03:00
Дмитрий
27dec3d459
docs(rules): аудит нормативки — закрытие 14 находок (CLAUDE.md v1.84 + Pravila v1.9 + PSR_v1 v1.5 + Tooling v1.13)
...
Audit конфликтов и запутанностей между CLAUDE.md / Pravila / PSR_v1 / Tooling
выявил 14 находок (3 🔴 high, 6 🟡 medium, 5 🟢 low). Все правки — через
paired stack: writing-plans → executing-plans → claude-md-improver (для
CLAUDE.md по §5 п.10) → verification-before-completion с grep-evidence.
Ключевые правки:
1. claude-md-management формализован #33 в Tooling §4.7 — пятый
включённый плагин (категория «инфраструктурная», вне UI-пула).
Tooling §0 счётчик 31 → 33 (3 off-phase tools).
2. Tooling §7 + PSR_v1 уровнем 3 — иерархия source of truth расширена
с 5 до 7 уровней, sync с CLAUDE.md §1.
3. Tooling §6 +5 конфликтов v1.4 — UPM↔FD, 21st↔Vuetify, 21st↔App*,
framer↔motion-v, UPM↔21st (с 5 до 10 строк).
4. Pravila §12.3 объявлен Single Source of Truth для exclusions §12;
PSR_v1 R0.4.A + CLAUDE.md §5 п.11 — cross-ref сюда.
5. Pravila §13.6 +tier-таблица hard-rule (explicit / transitive /
standard) — снимает скрытую иерархию между §12 и §13.9/§13.10.
6. PSR_v1 R10.1 разбит на 3 блока: enabledPlugins / built-in skills
Claude Code / MCP-серверы — раньше всё было одним списком.
7. PSR_v1 R8 +тай-брейкер FD↔21st (последовательно, FD ведущий).
8. PSR_v1 R10.4 + R14.7 — tier-метки transitive hard-rule с явным
указанием, что Pravila §9 «Отступления» к ним не применяется.
9. Scope-метки приоритетных цепочек — Pravila §0 (внутрипараграфный),
CLAUDE.md §1 (межфайловый), PSR_v1 R0.1 (scope головенства stack'а).
Снимает путаницу 4-х представлений.
10. CLAUDE.md §5 п.5 свёрнут до 2 строк со ссылкой на PSR_v1 R14
(был копией PSR_v1 на 12 строк).
11. Tooling §4.6 — settings.json → ~/.claude.json (где реально лежит
API-ключ 21st).
cspell-words.txt: +внутрипараграфный, внутрипараграфные, скилов
(новые термины из scope-меток и plan-файла).
Намеренно оставлено: R0.6 пункт 11 ⊂ пункт 6 (motion-специальный flow);
Pravila §13.10 формально избыточен (явная запись лучше транзитивного).
Plan: docs/superpowers/plans/2026-05-10-rules-audit-fixes-plan.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 05:06:16 +03:00
Дмитрий
b912724cf7
chore(frontend): Sprint 4 Phase C — bundle analyzer + dead-code cleanup (audit O-refactor-06)
...
- rollup-plugin-visualizer + script `npm run build:analyze` (env BUILD_ANALYZE=1)
Output: storage/bundle-analyze.html (gzip + brotli sizes), gitignored.
- cross-env установлен для Windows-совместимости env-переменной build:analyze.
- knip + knip.config.ts (entry app.ts + router/index.ts; ignore *.story.vue + tests/).
ВАЖНО: knip падает с oxc-parser ArrayBuffer fail на этой машине
(Windows quirk feedback memory) — конфиг сохранён для будущих запусков на
Linux/macOS CI. Dead-code search выполнен вручную через grep по composables/.
- Удалены 4 unused exports + 4 private helpers, инициируемых только ими:
* mockReports.ts: MOCK_JOBS, QuotaInfo (interface), MOCK_QUOTA
* reportsMapper.ts: reportTypes()
* mockTenantDetail.ts: expandTenantDetail() + 4 SAMPLE_* consts
(SAMPLE_USERS/SAMPLE_PROJECTS/SAMPLE_BALANCE_HISTORY/SAMPLE_ACTIVITY)
* useCsvDownload.ts: csvEscape() — снят `export` (используется внутри файла)
ESLint + vue-tsc + Vitest 416/416 + build — зелёные.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:59:58 +03:00
Дмитрий
79ff60ffd9
refactor(frontend): Sprint 4 Phase B/3 — split 2 utility views (audit O-refactor-04 хвост)
...
ErrorView 320→178 (+ ErrorBrand 54 + ErrorIllustration 31 + ErrorActions 55 + ErrorMeta 102).
DashboardView 302→84 (+ DashboardPageHead 65 + DashboardKpiRow 97 + DashboardBalance 124).
State (config, errorCode в ErrorView; range/kpis/balance в DashboardView) остаётся
в parent ради единого route.meta-driven flow + future API-fetch'а (Phase B/1 паттерн).
DashboardPageHead использует Vue 3.5 defineModel<T>() для двусторонней привязки range.
Sub-components читают только props — без Pinia stores (mock-data flow).
Все sub-components <250 строк (acceptance threshold). Shell line counts: 178/84.
ЗАМЕЧАНИЕ по acceptance «0 components >300»: НЕ закрыто полностью. 2 файла остались
выше порога — DealsView 560 + DealDetailDrawer 386. Зафиксировано в Sprint 3 Phase C
commit 6c2f0ce : bulk-action функции (applyBulkStatus/applyBulkDelete/applyBulkExport/
undoBulkDelete/applyBulkRestoreFromTrash) и comment/reminders fetch экспонируются
через defineExpose в Vitest-тестах напрямую — дальнейшая декомпозиция требует
изменения тест-контракта (отдельным flow, не вошло в Sprint 4 Phase B).
Phase B/3 закрывает 8/12 audit-кандидатов O-refactor-04: 3 в Sprint 3 Phase C
(Top-3) + 5 в Sprint 4 Phase B/1+B/2 (admin/layout/billing/security/reminders) +
2 в B/3 (errors/dashboard). Оставшиеся: 2 крупных deals-view (defineExpose-blocked)
+ ImpersonationDialog уже <300 органически.
Регрессия: ESLint 0 + vue-tsc 0 + Vitest 416/416 + build OK 989 ms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:53:09 +03:00
Дмитрий
849bc73290
refactor(frontend): Sprint 4 Phase B/2 — split 3 user views (audit O-refactor-04 хвост)
...
BillingView 416→114 (+ BalanceCard 155 + TransactionsTable 113 + InvoicesTable 90
+ billingFormatters 51 composable: formatPlain/formatCost/statusChipColor/
statusLabel/formatLabel/formatIcon/txAmountClass).
SecurityTab 354→39 (+ ChangePasswordCard 17 + TwoFactorCard 218 + RecoveryCodesCard 104
+ SessionsTable 66; auth-store читается напрямую в каждом sub-component).
RemindersView 345→183 (+ RemindersFilters 51 + RemindersList 173;
ReminderDialog уже отдельный с прошлой фазы — служит как ReminderForm).
State (`activeTab`, `editingReminder`, `deletingReminderId` в RemindersView)
остаётся в parent ради единого reload-flow + confirm-dialog'ов. Auth-store
читается напрямую в TwoFactorCard/RecoveryCodesCard через useAuthStore() —
без prop-drilling. Reminders-store читается напрямую в RemindersFilters/
RemindersList.
Все sub-components <250 строк (acceptance threshold). 3 view-shells: 114/39/183.
Регрессия: ESLint 0 + vue-tsc 0 + Vitest 416/416 + build OK 968 ms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:46:14 +03:00
Дмитрий
30ef61dff8
refactor(frontend): Sprint 4 Phase B/1 — split 3 admin/layout views (audit O-refactor-04 хвост)
...
3 view'а с >300 строк разделены на shell + sub-components:
AdminTenantsView 377→155 (+ TenantsStatsHeader 82 / TenantsFilters 93 / TenantsTable 116).
AdminTenantDetailView 436→109 (+ TenantDetailHeader 158 / TenantDetailTabs 176
+ adminTenantDetailFormatters 43 composable).
AppLayout 466→78 (+ AppSidebar 155 / AppTopbar 269; R0.6 hard-стоп снят
явным запросом заказчика 10.05.2026).
State (filterStatuses, tenantsState, activeTab, tenant, drawerOpen) остаётся
в parent view'ах ради `defineExpose`-контракта Vitest тестов. Sub-components
читают Pinia stores напрямую (auth + notifications + reminders) — без
prop-drilling.
AppTopbar 269 строк <300 — acceptance threshold выдержан (можно дальше split на
NotificationsDropdown + UserMenu в отдельном flow, не критично).
Регрессия: ESLint 0 + vue-tsc 0 + Vitest 416/416 + build OK 1.17 сек.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:38:08 +03:00
Дмитрий
cf1aabb32e
chore(cspell): добавлены UPM, gsap, LLM в словарь проекта
...
Сопровождает v1.83 docs-патч (PSR_v1 v1.4 формализация UPM + 21st Magic MCP).
Без этих записей pre-commit hook cspell блокирует коммит на CLAUDE.md /
PSR_v1 / Pravila / Tooling / CHANGELOG_claude_md, где термины используются.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:34:15 +03:00
Дмитрий
833e3e6083
docs(rules): PSR_v1 v1.4 — формализация UPM + 21st Magic MCP + R15 motion-системы
...
Триггер: пользователь спросил «хочу добавить плагины 21st, framer motion,
UI UX max — проанализируй конфликты». Проверка показала: UPM (skill) и 21st
Magic MCP (`magic` сервер) уже фактически включены в ~/.claude/settings.json
и ~/.claude.json, но в правилах не описаны. Framer Motion — React-only
runtime npm-библиотека, не Claude-плагин, физически не работает в Vue.
Через цикл brainstorming → 3 варианта → итерации согласовано: формализовать
UPM + 21st; для motion — двухуровневая R15 (framer-motion hard-запрет
навсегда + motion-v узкое окно по 4 условиям).
PSR_v1 v1.3 → v1.4 (главный артефакт):
- R6 → R6.0 универсальная таблица фильтра для FD/UPM/21st
- R6.1 hard-override Forest расширен на все три плагина
- R10.1 +21st row, ослабление UPM (FD молчит ИЛИ R12 третий вариант)
- R11.5 (новое) активация UPM в R12 архитектурном
- R11.6 (новое) иерархия 7 motion-источников
- R0.6 +3 hard-стопа (App* через 21st, Vuetify-эквивалент, motion-v)
- R13 +9 строк matrix'а
- R14 (новое, 7 подразделов) pipeline UPM + 21st
- R15 (новое, 7 подразделов) motion-системы
- R8 +7 тай-брейкеров
Pravila v1.7 → v1.8: §13 расширен на расширенный пул, §13.10 hard-link на R14.
Tooling Прил. Н v1.11 → v1.12: #31 UPM + #32 21st (off-phase tools), §9.2
motion-runtime denylist (framer-motion + react-spring R15.1; motion-v + gsap
+ anime + lottie + popmotion R15.2/R15.7). 31 формализованных позиций
(19/29 активных по фазам + 2 off-phase).
CLAUDE.md v1.82 → v1.83: §0 cross-refs, §2 +Animation default stack, §3.3
+#31 UPM +#32 21st, §5 п.5 расширен, §5 п.12 motion-runtime новый,
§6 обновлён, §9 +entry.
cspell-words.txt: +UPM +gsap +LLM (валидные термины проекта).
Через /claude-md-management:claude-md-improver. 6 файлов, 0 изменений
в коде проекта (resources/js/, app/, db/ нетронуты), 0 npm install.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:33:42 +03:00
Дмитрий
f77c91d5fa
feat(backend): Sprint 4 Phase A — keyset pagination в DealController::index (audit O-perf-04)
...
Опциональный query-параметр `cursor` (base64-encoded JSON {r:received_at, i:id}).
При cursor — keyset через PG row constructor `(received_at, id) < (?, ?)`
с использованием существующего индекса (received_at DESC, id DESC).
O(1) на любой глубине, без COUNT(*) (total не возвращается в keyset-режиме).
Без cursor — backward-compat OFFSET-путь: total + offset для существующего
frontend. Оба режима возвращают next_cursor (NULL = последняя страница).
Trick "+1 fetch" — узнаём про следующую страницу одним SELECT'ом без COUNT.
3 новых Pest-теста: keyset-навигация через cursor, 422 на невалидный cursor,
next_cursor flow. Pest 421/421 (419 + 2 skipped browser, +3 от 418 baseline).
phpstan-baseline.neon регенерирован: +2 occurrences pattern
`received_at?->toIso8601String()` (cursor build) + 7 occurrences тестовых
helper-properties Pest TestCall — все известные ignored patterns, не реальные ошибки.
Frontend integration в useDealsList/DealsView — отдельным шагом
(не блокирует backend deploy, OFFSET путь жив).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:29:54 +03:00
Дмитрий
8c6374d278
docs(spec-roadmap): fix broken link to memory/project_state.md (outside repo)
...
lychee pre-push hook поймал invalid markdown link на memory/project_state.md —
файл живёт в C:\Users\Administrator\.claude\projects\... (Claude auto-memory),
не в репозитории. Заменено на plain-text упоминание.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 04:12:58 +03:00
Дмитрий
823daf4f9f
docs(plan-sprint4): implementation plan «Audit tail» + revised spec scope
...
Sprint 4 — закрытие 3 оставшихся audit O-* пунктов:
- Phase A: O-perf-04 keyset pagination в DealController::index
- Phase B (1+2+3): O-refactor-04 хвост, split 8 Vue-компонентов >300 строк
- Phase C: O-refactor-06 dead-code detection через rollup-plugin-visualizer + knip
Spec ревизия: Sprint 4 уменьшен с 8 до 3 пунктов после факт-чека —
O-perf-07/O-refactor-05/O-refactor-07/O-stack-02/O-stack-03 уже закрыты
в Sprint 1–2 (Sprint 1 ESLint vuetify rule, Sprint 2 Phase A: Pest browser
scaffold, infection mutation, lazy-loading, Larastan cache; CLAUDE.md
header фактически 30 строк после 5b13c95 changelog extraction).
Финальная регрессия: Pest 419+ / Vitest 430+ / Larastan + ESLint + vue-tsc 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 03:57:46 +03:00
Дмитрий
77b018dff8
docs(spec-roadmap): дизайн roadmap'а до production — 3-track структура (A/B/C)
...
Покрывает категории A (audit-хвосты), B (Phase 3 tooling), C (Post-MVP backend),
D (Б-1-зависимые фичи), E (production deploy в YC). Категория F (юр. тексты) —
external; G (push 18 коммитов) — Sprint 0 precondition.
Двухдорожечная структура:
- Track A (Sprint 4–6): не зависит от Б-1, стартует сразу после push
- Track B (Sprint 7–9): после получения реквизитов ООО — YC infra + CI/CD + SSO + лендинг + hardening + soft-launch
Definition of done «production launch» в §1, per-sprint acceptance в §5,
9 рисков с mitigations в §6, 5 open questions для будущей детализации в §7.
Базовый HEAD: 6c2f0ce (после Sprint 3 Phase C).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-10 03:51:05 +03:00