Дмитрий
5f209a2fcc
fix(ui): косметика UI-аудита — даты дд.мм.гггг, инлайн-валидация, формат денег, aria, тосты, статус-метки, админка
...
Раунд 2 минор-фиксы (Playwright-аудит):
- RuDateField (новый): даты дд.мм.гггг через ru date-picker вместо нативного
<input type=date> (показывал мм/дд/гггг на en-локали) — Отчёты + Сделки.
- BalanceCapacityIndicator: разделитель тысяч «1 000 ₽», эмодзи→mdi.
- dealsApiMapper/DealDetailBody: статус-смена в активности русскими метками
(было «viewed → new» сырыми слагами).
- ProfileTab: инлайн-валидация Имя/Фамилия (под полем, как в Реквизитах).
- RequisitesTab: проверка формата телефона на клиенте.
- ApiTab: eye-toggle с aria-label (показать/скрыть ключ и секрет).
- DashboardView: «3 / 0» → скрываем «/ N» и «лимит тарифа» при лимите 0.
- KanbanView: тост-подтверждение при смене статуса (+ цветной фейл-тост).
- NotificationsTab: убран жаргон «users.notification_preferences в БД».
- Админка: TenantsTable «ИНН не указан» вместо пустого «ИНН »; PricingTiers
epoch-дата «1970»→«начала» + ru-формат цены; Incidents empty-state «Инцидентов
нет»; SupplierIntegration/PdSubjectRequests — window.confirm/alert → v-dialog/snackbar.
Верификация: type-check, build, Playwright (даты дд.мм.гггг подтверждены).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-21 17:08:51 +03:00
Дмитрий
95359d4ab3
fix(ui): убраны фейк-данные (ErrorView ID/статусы, фейк-фильтры отчётов) + эмодзи→mdi, англ-статусы→рус, пустой ИНН, склонение, формат денег, мёртвая кнопка
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
2026-06-21 12:52:58 +03:00
Дмитрий
ca5fd8d2f6
fix(G3): счётчик «7 событий» в уведомлениях + убрать «напоминаниях» из подсказки таймзоны
...
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Хвосты, пойманные живым Playwright: захардкоженное «8 событий» после удаления reminder-события + stale-подсказка профиля.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 12:06:17 +03:00
Дмитрий
4c3e57bf9b
feat(G3): убрать преференцию «Напоминание» + хвосты фронт-тестов
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-06-19 11:29:46 +03:00
Дмитрий
3440483bd7
feat(G1/SP3c): блок платёжных реквизитов + статус-чип + валидация (поля по типу лица)
...
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-19 07:58:47 +03:00
Дмитрий
f88fd7ad98
feat(G1/SP3b): вкладка RequisitesTab — лёгкая форма реквизитов
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-19 07:24:26 +03:00
Дмитрий
41adf00cba
feat: G4 убрать неработающий push-канал из настроек уведомлений + находка G8 про сломанный фронт-тест-раннер
...
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-18 13:46:31 +03:00
Дмитрий
7b04e7e752
feat(settings): D6/D7 — убрать placeholder-вкладки SettingsView
...
Audit findings D6/D7 (Sprint 3E): убраны 4 placeholder-вкладки
(Проекты/Команда/Интеграции/Тихие часы) из SettingsView — UI не должен
обещать неработающий функционал. Удалён PlaceholderTab.vue. Остались
4 рабочие вкладки: Профиль, Безопасность, API и Webhook, Уведомления.
Тесты: 8/8 SettingsView.spec.ts ✓, Vitest 100f/838/3sk/0 ✓.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-16 14:25:42 +03:00
Дмитрий
c693d03a75
test(settings): ApiTab — load error-path coverage + idiomatic disabled check (review M2/M3)
...
Code-quality review of Task 5: adds tests for the loadApiKey/loadWebhook
catch branches (apiKeyError/webhookError -> error v-alert) and changes
the Copy-button disabled check to the idiomatic falsy form.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-15 22:35:49 +03:00
Дмитрий
298a7fa9de
feat(settings): ApiTab wired to api-key + webhook endpoints (closes D2-D5)
...
Audit D2/D3/D4/D5: all four ApiTab buttons were handler-less and the
fields were hardcoded. Adds api/apiKeys.ts + api/webhooks.ts modules and
rewires ApiTab: loads the api-key prefix + webhook settings on mount;
Copy -> clipboard + snackbar; Regenerate -> confirm dialog -> POST
regenerate (full key shown once); Save Webhook -> PUT webhook-settings;
Test Webhook -> POST test with the result in a snackbar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-15 22:27:56 +03:00
Дмитрий
2c59a00714
refactor(settings): ProfileTab — document auth-guard assumption + tighten spec (review M1/M2)
...
Code-quality review of Task 2: documents why ProfileTab needs no
watch-resync of auth.user (router beforeEach awaits fetchMe before
requiresAuth navigation); tightens the save-error test to assert the
exact fallback message instead of mere truthiness.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-15 21:44:17 +03:00
Дмитрий
075a661c62
feat(settings): ProfileTab wired to PATCH /api/auth/me (closes D1)
...
Audit D1: ProfileTab fields were hardcoded refs and the Save button had
no handler. Rewired to the auth store + a new api/auth updateProfile()
calling PATCH /api/auth/me. Single «Полное имя» field split into Имя +
Фамилия (matches users.first_name/last_name); decorative «Роль» field
removed (no such column). AuthUser type gains phone + timezone.
SettingsView.spec.ts updated: «Полное имя» assertion changed to check
for «Имя» and «Фамилия» (collateral fix for the intentional field split).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-15 21:37:40 +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
Дмитрий
f55b91cfa4
phase2(notifications-stage3): NotificationsTab schema-aligned + prefs API
...
Закрывает архитектурное расхождение v1.28 — Tab сохранял prefs только
локально без API. Backend events не совпадали с handoff'ом.
Backend:
- PATCH /api/auth/me/notification-preferences под auth:sanctum.
- Replace-семантика: незадекларированные events/channels отбрасываются.
- userResource расширен: notification_preferences + sound_enabled.
- UserFactory с schema-default JSON (Eloquent не перечитывает после INSERT,
DB-DEFAULT JSONB виден как null без явного override).
- Pest +10: 401 / replace / неизвестные events/channels отбрасываются /
422 без prefs / sound_enabled опционален / bool-cast 1/'1' / replace-
семантика (отсутствующие events исчезают).
Frontend:
- api/auth.ts: типы NotificationChannel/EventKey/Preferences +
updateNotificationPreferences helper. AuthUser получил optional поля.
- NotificationsTab.vue переписан под schema:
8 событий (new_lead/reminder/low_balance/zero_balance/topup_success/
invoice_paid/new_device_login/marketing) × 3 канала (inapp/push/email,
НЕ sms). Sync-init prefs (без onMounted — иначе v-if блокирует рендер
и тесты mount-then-find падают). dirty через computed-сравнение с
originalPrefs snapshot. save async + success/error alerts.
- SettingsView.spec.ts: legacy event-имена → schema-aligned.
- Vitest +10: 8 schema events / 3 channels (НЕ sms) / legacy отсутствуют /
читает prefs из user / save calls API + alerts / Отменить возвращает.
cspell-words: +prefs.
PHPStan baseline регенерирован.
Pest 315/315 (+10) за 36.73 сек, 1130 assertions.
Vitest 349/349 (+10) за 20.42 сек.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 11:41:35 +03:00
Дмитрий
73e64128dc
phase2(2fa-setup): wizard init+confirm+disable+regenerate в SettingsView/SecurityTab
...
- TwoFactorSetupController (auth:sanctum): /api/2fa/{init,confirm,disable,regenerate-recovery-codes}
- init секрет в session (не в БД), QR-URL otpauth://; confirm активирует 2FA + 8 recovery codes
- disable/regenerate требуют password-confirmation
- User.casts: totp_secret => encrypted
Schema v8.7→v8.8: users.totp_secret VARCHAR(255) → TEXT (encrypted ~256 chars)
Migration fix: explicit ALTER TABLE webhook_dedup_keys ADD FK после DB::unprepared (PDO глотал FK на partitioned)
PartitionsCreateMonthsTest fix: DETACH PARTITION + DROP вместо DROP CASCADE
Frontend: SecurityTab реальная логика (setup wizard 3 шага, disable, regenerate dialogs)
- Pest +10 (101/101 за 13.37с, 364 assertions)
- Vitest 166/166
- CLAUDE.md v1.39→v1.40, реестр v1.48→v1.49, schema v8.7→v8.8
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 04:03:02 +03:00
Дмитрий
394663597f
phase2(settings): SettingsView - 8 вкладок (4 реализованы, 4 placeholder)
...
- SettingsView (/settings): sidebar tabs-rail (md=3, 8 v-list-item с mdi-icon)
+ content-pane (md=9 v-card outlined min-height 480px). activeTab ref
переключает рендер вкладки.
Реализованы:
- ProfileTab: avatar 80px + 5 form-fields (имя/email disabled/телефон/TZ/роль).
- SecurityTab: 3 cards (Пароль / 2FA включена + recovery codes + Отключить /
Активные сессии 3 mock с Завершить-btn).
- ApiTab: API-ключ password+eye-toggle + Webhook (URL + signing secret HMAC).
Текст про дедуп (tenant_id, source_crm_id) 24ч и антифрод по phone (§10.8.1).
- NotificationsTab: матрица 8x3 (events × channels) соответствует schema v8.7
§4 users.notification_preferences JSONB. 8 событий (new_lead, duplicate_detected,
low_balance, tariff_charge, reminder_due, manager_assigned, webhook_failed,
monthly_report) × 3 канала (email/sms/in_app). + sound_enabled switch.
Placeholder:
- PlaceholderTab универсальный с props title/description + v-alert «В разработке».
- Используется для Проекты / Команда / Интеграции / Тихие часы.
Маршрут /settings (meta.layout=app, lazy-import) в router + web.php.
.gitleaks.toml: settings/*.vue в allowlist (фиктивный профиль).
cspell-words.txt: смыслово.
Vitest +8 (всего 98/98 за 8.42s):
- 8 nav-tabs + все названия + дефолт «Профиль» + Проекты → «В разработке» +
Уведомления показывает «События × каналы» + 5 событий матрицы +
Безопасность: 2FA + сессии + API: API-ключ + Signing secret HMAC.
Регресс: lint+type+format OK; vitest 98/98; vite build (SettingsView lazy-chunk;
main app-chunk 107.85KB); story:build 17/24 за 31.7s; Pest 48/48 за 5.03s.
CLAUDE.md v1.27->v1.28, реестр Открытых_вопросов v1.36->v1.37.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-08 18:51:41 +03:00