Commit Graph

667 Commits

Author SHA1 Message Date
Дмитрий 3fdfa4a2ee feat(billing): YooKassaDriver — создание платежа и server-to-server сверка 2026-06-22 20:36:17 +03:00
Дмитрий 5c0e3760f6 feat(billing): интерфейс PaymentGatewayDriver + DTO результата платежа и сверки 2026-06-22 20:33:22 +03:00
Дмитрий fa05fc38fb feat(billing): флаги billing_yookassa_enabled/billing_receipt_enabled + хелпер SystemSettings 2026-06-22 20:32:18 +03:00
Дмитрий 6aeeff24d3 feat(billing): Eloquent-модели legal_entities/payment_gateways/saas_transactions 2026-06-22 20:26:47 +03:00
Дмитрий a2e73a3d4d feat(support): виджет онлайн-чата JivoSite (спит без ключа)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- JivoWidget.vue: подгружает скрипт Jivo при заданном VITE_JIVO_WIDGET_ID
  (по образцу SmartCaptchaWidget); ключ пуст → ничего не грузит, виджет спит.
- Смонтирован в AppLayout (клиентский портал). +VITE_JIVO_WIDGET_ID в vite-env.d.ts.
- TDD: JivoWidget.spec (грузит при ключе / спит без) GREEN; AppLayout.spec 16/16; eslint 0.
- Активируется вставкой VITE_JIVO_WIDGET_ID (твой ID канала Jivo). На прод не выкачено.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 19:19:58 +03:00
Дмитрий eb1ab278fe fix(reports): сбрасывать зелёный «отчёт создан» при отмене задачи (ui-audit минор)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- ReportsView.onCancel снимает submitSuccess — success-баннер больше не висит после отмены отчёта. TDD: тест «отмена задачи сбрасывает зелёный» (RED→GREEN), весь ReportsView.spec 22/22, eslint 0.
- docs: ui-audit-round2 — минор тоста помечен исправленным (открытых пунктов не осталось); stage5-checklist — supplier:rekey-orphans dry-run проверен на проде 22.06 («No orphan»), разовая миграция не нужна.
- На прод не выкачено.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:32:10 +03:00
Дмитрий 60c640e88a feat(db): RLS на tenants + created_at TZ (schema v8.51)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
2026-06-22 18:03:42 +03:00
Дмитрий 3630e71620 feat(projects): клиентская валидация формы нового проекта (F-NEWPROJECT-1) + синк статусов находок по проду
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
- NewProjectDialog.submit(): обязательны название и источник (домен/номер/отправители по типу сигнала); ошибка показывается сразу, без обращения к серверу. +2 TDD-теста, два существующих теста обновлены под новый гейт. Полный фронт-сьют — без новых падений; проверено глазами в браузере на локалке.
- docs: пометки находок приёмки/UI/impersonation/ADR-018 приведены к фактическому прод-статусу (M-1, M-2 капча Yandex, FN-RESET/2/3/ENC, F-CSV, apiv1-rate, N-4, F-T1, F-P1 — на проде; failed_jobs очищены 494191->0; tenant 24 удалён soft-delete).
- решение владельца 22.06: admin-area доделки (saas-admin SSO, two-person approval, role-guard супер-админа, supplier fallback, обезличенный admin_user_id) сняты как отдельные задачи — доделать единым пакетом вместе с подключением Yandex SSO после ООО.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 16:43:10 +03:00
Дмитрий 8cc09d4509 fix(ui): биллинг — «Запас» по живому заказу, убрать дубль и строку-чтение
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Поправки после первой версии (по замечаниям владельца):
- «Запас» считаем по текущему заказу проектов (requiredLeadsPerDay), так же как
  BalanceCapacityIndicator: 0/день → ∞ (баланс не расходуется), N/день → лиды/N.
  Раньше брался бэкендный runway_days (историческая скорость за 30 дней) —
  давал «2192 дн.» рядом с «при 0 лидов в день», выглядело фейком/противоречиво.
- Убрана строка-чтение под рядом (дубль).
- Убран BalanceCapacityIndicator из BillingView: дублировал ряд и писал
  «по тарифу», хотя тарифов нет.
- Рамки трёх карточек выровнены по высоте (единый border/radius + flex-stretch,
  убран конфликтный height:100%).

Тесты BalanceCard/BillingView обновлены. vitest 19/19, vue-tsc и build — зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 13:20:14 +03:00
Дмитрий b21e07a2a7 feat(ui): биллинг — убрать «Тариф», ряд Деньги → Лиды → Запас
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Тарифов как сущности нет (цена за лид считается по объёму, 7 ступеней) —
карточка «Тариф» («не выбран» + вечно-неактивная кнопка) убрана. На её место —
«Запас» (runway_days): на сколько хватит баланса при текущем заказе. Ряд связан
стрелками + строка-чтение «N ₽ = M лидов = надолго / на K дн.». Число лидов
теперь с разделителем тысяч. Дубль «хватит на N дн.» убран из шапки.

Тесты BalanceCard.spec / BillingView.spec обновлены под новую структуру.
Сборка и vue-tsc — зелёные.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 12:58:57 +03:00
Дмитрий cab741f8d8 fix(приёмка): FN-AUDIT — verify-chains авто-закрывает устаревшие инциденты целой цепочки
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
При зелёной проверке всех партиций таблицы audit:verify-chains теперь закрывает
оставшиеся открытые инциденты разрыва hash-chain по этой таблице. Убирает класс
вечно-открытых ложных инцидентов после транзиентного разрыва — например строк
тест-тенантов приёмки, удалённых teardown.

Диагностика прогона 22.06: 4 m06-инцидента 576-579 были только по строкам
тест-тенантов; teardown их удалил, боевые цепочки tenant 2 целы.

TDD: 2 теста (целая таблица закрывает инцидент; сломанная — не трогает).
Pint и Larastan чисто, регрессий нет.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 10:57:10 +03:00
Дмитрий 7fd3cde4f6 fix(приёмка): FN-ENC — битый UTF-8 в CSV-импорте ронял очередь
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Один невалидный UTF-8-байт в выгрузке лидов crm.bp-gr.ru ронял весь импорт на
INSERT (PG: invalid byte sequence for encoding UTF8, SQLSTATE 22021). str_getcsv
пропускает любые байты, и невалидная последовательность доходила до БД.
CsvLeadsParser::parse теперь чистит невалидный UTF-8 через mb_convert_encoding
до парсинга — битый байт заменяется, строка импортируется, очередь не падает.
TDD CsvLeadsParserUtf8Test, проверено руками на PG.

Также зафиксирован вывод по FN-RLS-CTX: no-action — путь projects уже под
tenant-middleware, старый no-auth endpoint заменён, не воспроизводится.

Прод не трогался. Накат — позже вместе с остальным.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:43:02 +03:00
Дмитрий 37a8a5c17f fix(приёмка): FN-2 + FN-3 — мёртвый reminder в DEFAULT и email_verified_at при confirm
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
FN-3: онбординг-confirm не ставил users.email_verified_at — поле вне fillable,
mass-assign его гасил. RegistrationService::confirm теперь forceFill is_active +
email_verified_at. TDD ConfirmSetsEmailVerifiedAtTest.

FN-2: миграция 2026_06_19_130000 дропнула таблицу reminders, но забыла
ALTER COLUMN notification_preferences SET DEFAULT — реальный DB-дефолт оставался
с мёртвым ключом reminder, расходясь с каноном schema.sql v8.45. Новая миграция
2026_06_22_120000 метаданные-only выравнивает дефолт под канон. squawk 0 issues,
применено dev+testing, проверено psql. CHANGELOG v8.50 + шапка schema.sql.
TDD NotifPrefsDefaultNoReminderTest.

FN-1 переоценён как не-баг кода: resolvePlatforms даёт B2+B3 корректно, B3-miss —
supplier-side Doubles, джоба сама ретраит. Зафиксировано в отчёте приёмки.

Прод не трогался. Накат — позже вместе с остальным.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 09:20:42 +03:00
Дмитрий e8e5c82b86 fix(приёмка): FN-RESET + FN-LOGIN-ROUTE + диагностируемость FN-SESSION
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
FN-RESET: письмо сброса строило именованный роут password.reset которого нет в SPA.
ResetPassword::createUrlUsing → /reset/{token}?email= в AppServiceProvider boot.

FN-LOGIN-ROUTE: гость без Accept json на auth:sanctum уводил в именованный роут
login которого нет → 500. redirectGuestsTo /login + render AuthenticationException
→ 401 JSON для api/*.

FN-SESSION: chromium.launch стоял вне try/catch — отказ запуска браузера маскировался
unhandled-rejection в opaque exit 1 двойник login-rejected. launch в try + top-level
catch → чистый exit 4 + JSON stderr в refresh-session.js и manage-project.js.

Тесты: PasswordResetUrlTest, UnauthenticatedApiResponseTest, node:test launch-failure
в обоих playwright-скриптах. Разбор FN-SESSION + ops-долг playwright install под
www-data + поправки отчёта приёмки + новая находка FN-INN-LOOKUP.

Прод не трогался. Накат — позже вместе с остальным.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 08:49:19 +03:00
Дмитрий 89ed1714e8 style(test): импорт Collection в digest-тесте (lint-фиксап, функц. идентично)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:45:21 +03:00
Дмитрий 2225a8487e feat(security): рабочая «Завершить сессию» — реальный отзыв активных сессий
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
UI-аудит: вкладка Безопасность показывала фейк-сессии с мёртвой кнопкой.
Теперь — реальные активные сессии + рабочий отзыв.

- UserSessionTracker (новый): запись сессии при входе (login + 2FA verify +
  recovery-use) в существующую таблицу user_sessions; отзыв = удаление строки
  + удаление сессии из Redis по session_id (реальный выход с устройства);
  logout снимает текущую сессию из списка. Best-effort (не ломает вход/выход).
- AccountController: GET /api/account/security отдаёт реальные сессии;
  DELETE /api/account/sessions/{id} — отзыв (только свои; чужая → 404).
- Фронт SessionsTable: список + кнопка «Завершить» (кроме текущей).
- phpstan-baseline обновлён (Pest-$this нового теста).

Pest: 10/10. Верификация: Playwright (2 сессии → «Завершить» → исчезла).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:15:26 +03:00
Дмитрий e15494c8ad fix(приёмка): N-2 детерминированная уборка orphan-таблиц + N-4 надёжный дедуп дайджеста
N-4: пометка digest_sent ПОСЛЕ отправки (mark-after-send) — повтор не
дублирует И сбой джоба до отправки не теряет дайджест. TDD-тест GREEN 6/6.
N-2: инъекции R2 с TEST-диапазоном vid 9e12..1e13 → R5 чистит 4 orphan-таблицы
детерминированно по vid/lead_id, без ручного манифеста.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 16:10:57 +03:00
Дмитрий ec6434ee9a feat(security): реальная смена пароля + недавние входы вместо mock-заглушек
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
UI-аудит раунд 2, вкладка «Безопасность» — убраны фейк-данные и мёртвые кнопки.

Backend (schema-free, без смены SESSION_DRIVER):
- AccountController + ChangePasswordRequest: POST /api/account/change-password —
  проверка текущего пароля (Hash::check против password_hash), новый >=10 симв +
  confirmed, лог password_changed/password_change_failed в auth_log (hash-chain).
- GET /api/account/security: last_password_change_at (max по password-событиям
  auth_log) + recent_logins (реальные login_success: устройство/IP/время).
- Роуты под auth:sanctum + throttle:auth-password.
- Pest: 6 тестов. Регрессия Account+Auth — 23/23 GREEN. phpstan-baseline обновлён
  (Pest-$this false-positives нового теста, как у прочих тестов).

Frontend:
- api/account.ts.
- ChangePasswordCard: реальная дата + диалог (текущий/новый/подтверждение,
  show/hide, обработка 422 неверного текущего пароля).
- SessionsTable -> «Недавние входы»: реальный список из API, убраны 3
  захардкоженных фейк-сессии + мёртвая кнопка «Завершить».

NB: индивидуальный отзыв cookie-сессий требует database-драйвера сессий
(инфра-решение владельца) — отдельный follow-up. Сейчас входы — честный read-only.

Верификация: type-check, build, Playwright (диалог: неверный->ошибка,
смена->дата 21.06, восстановление password123; недавние входы — реальные).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 15:03:43 +03:00
Дмитрий 0c26afd03e fix(admin): починка 500 на admin-сохранениях (audit-id из config, без saas_admin_users) + тариф текущей датой
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
2026-06-21 11:32:53 +03:00
Дмитрий 7606e69dbc fix(captcha): актуальный validate-URL Yandex SmartCaptcha smartcaptcha.cloud.yandex.ru (сверено по докам)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
2026-06-21 09:15:20 +03:00
Дмитрий 12eace3699 feat(security): реальный Yandex SmartCaptcha драйвер самозаписи по CAPTCHA_DRIVER (M-2)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
2026-06-21 09:02:31 +03:00
Дмитрий d7b5f2c103 test(coverage): расширение охвата Раздел B №2-5 — границы reminder/final, терминальные пути оркестратора, G6 API edges 2026-06-21 08:41:03 +03:00
Дмитрий b9184a6aea test(supplier): regression-guard неизменности received_at при merge CSV-recovered сделки 2026-06-21 08:23:13 +03:00
Дмитрий d784df50a8 fix(security): fail-closed app-гейт админ-зоны по REMOTE_USER и allowlist — M-1 2026-06-21 08:11:02 +03:00
Дмитрий 255680cf0f feat(api): rate-limit публичного /api/v1/deals 120 в минуту на источник перед apikey 2026-06-21 08:10:22 +03:00
Дмитрий 825b02cf72 fix(digest): идемпотентность дайджеста новых сделок по сделке (N-4)
N-4: SendNewLeadsDigestJob выбирал сделки received_at>now()-30min без маркера
отправки → ручной/повторный прогон (R3b велит дёргать вручную) дублировал
письмо-дайджест. Окно «непересекается» только при ровно-30-мин прогонах.

Фикс без схемы: идемпотентность по сделке через Redis SETNX
(Cache::add 'digest_sent:<id>', TTL 1 сутки) — паттерн как rate-limit
ZeroBalancePausedMail. Уже отправленная сделка в дайджест повторно не входит.

TDD: тест «повторный прогон НЕ дублирует» (RED 2 письма → GREEN 1), сюит 5/5.
R3b DIGEST-ON + owner-decisions + NEW-статус обновлены (N-4 → закрыто).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 07:01:10 +03:00
Дмитрий 862243a2b8 fix(reports): защита от CSV/formula-инъекции в писателях-форматтерах (F-CSV-wide)
Ревью раунда 2: F-CSV шире — формула может уйти не только через DealExport, но
и через центральные писатели ОТЧЁТОВ (Managers/Sources/Billing/Deals × csv/xlsx).
Прежний фикс нейтрализовал в DealsExportProvider — неверный слой: он кормит и
JSON-формат, где апостроф портил данные (ReportJobControllerTest).

Перенос защиты в писатели:
  - CsvFormatter — CsvFormulaGuard::neutralizeCell (апостроф, числа не трогаются)
  - XlsxFormatter — опасные строки через setCellValueExplicit TYPE_STRING
    (Excel НЕ вычисляет формулу; XLSX опаснее — считает без предупреждения)
  - DealsExportProvider — откат к сырым данным (JSON больше не портится)
CsvFormulaGuard: + isDangerous()/neutralizeCell() — numeric-aware (ведущий «-»
числа не экранируется).

TDD: unit-тесты CsvFormatter + XlsxFormatter (load xlsx → datatype 's', не 'f').
DealExportController (OpenSpout, отдельный путь Сделок) — без изменений.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 05:23:42 +03:00
Дмитрий 6b9a7636ae fix(export): защита выгрузок сделок от CSV/formula-инъекции
F-CSV: ячейки экспорта писались «как есть» — значение вроде =HYPERLINK(...)
или @SUM(...) в комментарии/контакте/городе при открытии файла в Excel/
LibreOffice исполнялось как формула (OWASP Formula Injection).

Новый App\Support\CsvFormulaGuard::neutralize() префиксует апострофом ячейку,
начинающуюся с = + - @ TAB CR. Применён к свободному тексту в:
  - DealExportController (телефон/источник/город/статус/комментарий)
  - DealsExportProvider  (телефон/контакт/статус/проект/менеджер)
Числовые колонки (id/суммы/даты) не трогаются — ведущий «-» там легитимен.
TenantChargesController НЕ уязвим: колонки enum(CHECK)/число/дата, свободного
текста нет.

TDD: 13 unit-тестов хелпера + feature-тест экспорта сделок + provider-тест.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 04:45:30 +03:00
Дмитрий c5840ea25d refactor(impersonation): отправку письма о завершении сессии вынести в сервис
F-DEPTRAC: middleware ImpersonationContext зависел от слоя Mail
(ImpersonationEndedMail) — нарушение deptrac ruleset, блокировало ВСЕ
php-коммиты. Отправка письма + завершение сессии вынесены в новый
ImpersonationExpiryService (Service-слой, которому Mail разрешён,
идемпотентно). Middleware теперь зависит только от Service.

deptrac: 0 нарушений. TDD: 2 теста сервиса (письмо в очереди + идемпотентность).
phpstan-baseline.neon перегенерён под Pest $this-false-positives новых тестов
этой серии правок приёмки (level 5, composer stan = 0).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 04:43:16 +03:00
Дмитрий 173b089629 feat(G7-B): клиентская плашка impersonation + редирект/ключ в диалоге + leave 2026-06-19 17:09:59 +03:00
Дмитрий a2f086cc40 feat(G7-B): leave из кабинета + impersonation-контекст в /api/auth/me + end-письмо 2026-06-19 17:04:48 +03:00
Дмитрий 56f54dfdb7 feat(G7-B): изоляция админ-зоны при impersonation + авто-истечение сессии 1 ч 2026-06-19 16:51:21 +03:00
Дмитрий 3e1eb7e835 feat(G7-B): guard impersonation + envelope машинного ключа на рабочих группах кабинета
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 16:44:42 +03:00
Дмитрий 377a16a605 feat(G7-B): verify — session-takeover целевого юзера + выдача машинного ключа 2026-06-19 16:35:03 +03:00
Дмитрий ab0787c887 feat(G7-B): письма impersonation код-согласие + завершение, wire в init 2026-06-19 16:25:49 +03:00
Дмитрий bfdc45b757 feat(G7-A): POST /api/support-requests + тест (store+mail+валидация)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:00:12 +03:00
Дмитрий 2eaa78f95b fix(stan): Larastan-долг G1/G6 = 0 ошибок (реальные баги — починены, не спрятаны)
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Продуктовый код (фиксы, не baseline): TenantRequisites+SupplierLead — явные @property (ide-helper:models пропускал модели); DealsController V1 — лишний ?-> на non-null received_at; ScrubPii — guard instanceof Monolog. Тест-код: ImitationTestCase @param int; findByInn return-type. Baseline перегенерён — в нём ТОЛЬКО ложноположительные (Pest TestCall + защитный ?-> на nullable first() в debug-строках ScenarioBC), 0 продуктовых подавлений (проверено диффом). composer stan: 0.

NB: столбцы lead-region (dadata_qc/phone_operator/region_source/resolved_subject_code) есть в БД, но отсутствуют в db/schema.sql — отдельный дрейф схемы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:40:00 +03:00
Дмитрий 6bbfa1f624 fix(G3): убрать создание reminders из HistoricalImportService (шов CSV-импорта)
CSV-колонку «Напоминание» парсер по-прежнему читает (внешний формат), но строки-напоминания больше не создаются — модель Reminder удалена.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:43:00 +03:00
Дмитрий 582c02d4a7 feat(G3): убрать reminder из дефолтов notification_preferences (factory+seeder)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:38:58 +03:00
Дмитрий 34981da707 feat(G3): удалить контроллер/роуты/модель/команду/письмо напоминаний
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:37:57 +03:00
Дмитрий c85b4acbc3 feat(G3): убрать ветку reminder из NotificationService
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:36:27 +03:00
Дмитрий 591abc7d93 feat(G3): убрать next_reminder_at-подзапрос из DealController
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:34:36 +03:00
Дмитрий 4c3e57bf9b feat(G3): убрать преференцию «Напоминание» + хвосты фронт-тестов
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:29:46 +03:00
Дмитрий cbf8b4fb43 feat(G3): убрать next_reminder_at из фронт-слоя сделок
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:29:35 +03:00
Дмитрий a49b201d33 feat(G3): убрать экран «Напоминания» и раздел в карточке сделки
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:18:49 +03:00
Дмитрий c61c38efd4 test(G6): приёмка публичного API сделок (RED)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 10:11:24 +03:00
Дмитрий 9c73d99ad6 test(G2-B): дефолт new_lead.email=true (RED) + backfill SQL
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:51:04 +03:00
Дмитрий 8fc63d5782 fix(G1-tail): письмо с кодом в очередь + не валить register/resend при сбое доставки
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Owner-decision: register не должен падать 500 при сбое SMTP — код уже создан,
клиент может «отправить повторно». Mail::queue + try/catch + Log (без email — ПДн).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:29:15 +03:00
Дмитрий 082a67363e fix(G1-tail): убран стейл-Шаг 6 (webhook_log удалён в v8.35) из OperationalFullFlowTest
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 08:18:30 +03:00
Дмитрий 799d416b9a fix: дополнен мок DashboardSummary в DashboardView.spec (avg_lead_cost_rub) — type-check green
Пред-существующая type-ошибка (поле required в DashboardSummary отсутствовало в моке). Не связано с SP3a; убирает единственную ошибку vue-tsc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 23:45:08 +03:00