Дмитрий
|
cb05657f30
|
chore(format): prettier --write across 37 .vue/.ts files
Phase 1B audit found 48 files failing `prettier --check`. Auto-apply
via `npx prettier --write resources/js/**/*.{ts,vue,css}` produced
style-only changes:
- consistent quote style
- trailing comma normalization
- spaces around : in v-card style="position: relative" attrs
- explicit ; insertion
No semantic changes. No code-behavior changes. Production-code only;
test files batched separately into `test(frontend):` commit.
Verification:
- npx vitest run → 79/79 files, 614/614 + 3 skipped (no regression).
- npx vue-tsc --noEmit → 0 errors.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-12 20:24:33 +03:00 |
|
Дмитрий
|
a09434eca0
|
feat(redesign): Task 13 — page transition wiring (Vue Transition + CSS fadeup, motion #6)
|
2026-05-12 09:59:22 +03:00 |
|
Дмитрий
|
0245f12b51
|
chore(dev): inject DevIndexBadge for visual feature feedback on localhost
|
2026-05-12 04:45:18 +03:00 |
|
Дмитрий
|
c9ee8d866e
|
feat(frontend): Plan 5 Task 7 — router + nav + regions + ProjectCard + story
|
2026-05-11 19:31:23 +03:00 |
|
Дмитрий
|
0f820c4569
|
feat(admin): Plan 4 Task 10 — AdminSuppliersController + AdminSupplierPricesView (B1/B2/B3 cost editor)
Backend AdminSuppliersController:
- GET /api/admin/suppliers — все 3 поставщика (B1/B2/B3).
- PATCH /api/admin/suppliers/{id} — обновляет cost_rub / quality_score / is_active.
- Validation: cost_rub >= 0, quality_score 0..9.99.
- Audit trail saas_admin_audit_log (stub admin via system-supplier@liderra.local).
- 4 Pest integration tests.
Frontend AdminSupplierPricesView (Vue 3 + Vuetify 3):
- v-data-table 3 строки с inline-editing cost_rub/quality_score/is_active.
- Forest-palette + JetBrains Mono tnum.
- 3 Vitest tests + Histoire story.
Router /admin/supplier-prices route.
Drive-by fix: SupplierProjectFactory.definition() default signal_type
ограничен ['site','call'] — иначе при ->create(['platform' => 'B1']) с
оригинальным random 'sms' нарушается CHECK chk_supplier_projects_b1_not_for_sms
(flaky parallel-pest race condition). Тесты, которым нужен 'sms', продолжают
явно передавать signal_type вместе с B2/B3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-11 11:28:03 +03:00 |
|
Дмитрий
|
ed5e3f495d
|
feat(admin): Plan 4 Task 9 — AdminPricingTiersController + AdminPricingTiersView (CRUD 7-tier + audit)
Backend AdminPricingTiersController:
- GET /api/admin/pricing-tiers — active + scheduled.
- POST — create 7-tier set с effective_from=DATE_TRUNC('month', NOW()+1 month).
- DELETE /scheduled/{date} — отмена будущей сетки.
- Validation: ровно 7 tier_no 1..7 unique, tier 7 leads_in_tier=null, price>=0.
- Audit trail saas_admin_audit_log на POST + DELETE (через SaasAdminAuditLog
model: payload_before/after, NOT NULL admin_user_id резолвится через стаб
system-pricing@liderra.local + ip_address из $request->ip()).
- 8 Pest integration tests.
Frontend AdminPricingTiersView (Vue 3 + Vuetify 3):
- v-data-table активной сетки + scheduled groups + dialog editor.
- Forest-palette + JetBrains Mono для tnum-цифр.
- 5 Vitest unit tests (tests/Frontend/, авто-импорт Vuetify через vite-plugin).
- Histoire story для preview.
Router /admin/pricing-tiers route (layout 'admin', requiresAuth).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-11 11:18:01 +03:00 |
|
Дмитрий
|
dc1457a008
|
phase2(reminders-frontend): RemindersView + DealDetailDrawer + nav-badge
P0 этап 5 — frontend для reminders (после backend-этапа 4).
Пользователь может создавать/просматривать/завершать/удалять напоминания
из UI с inline-create в DealDetailDrawer.
Frontend:
- api/reminders.ts: типизированные helpers для 5 endpoints + ensureCsrfCookie
для mutating. Types ReminderFilter/ApiReminder/ReminderCounts.
- stores/reminders.ts: Pinia с items/counts/currentFilter +
load/refreshCounts/create/update/complete/remove. Optimistic для
complete/remove с revert на reject.
- components/reminders/ReminderDialog.vue: dual-mode (create/edit) modal
с native datetime-local input. Props dealId?/reminder? (edit),
ISO-конверсия при submit.
- views/RemindersView.vue: page-head с stats (active/overdue) + reload-btn;
4 tabs (today/upcoming/overdue/completed) с counts на бейджах
(overdue=error color); v-list с complete-btn / dropdown
Изменить/Удалить с confirm-dialog; empty-state.
- router: /reminders маршрут (lazy).
- AppLayout: nav-badge «Напоминания» биндит count из store
(replace static «12»); скрыт при count=0; polling 60 сек для
refreshCounts.
- DealDetailDrawer: секция «Напоминания» (только при tenantId+deal):
inline + create-btn / список / complete / встроенный ReminderDialog.
Vitest +20 (369/369 за 21.20 сек):
- reminders-store 11: initial / load+reject / refreshCounts /
create+reject / complete optimistic+revert / remove+reject / reset.
- RemindersView 7: mount / 4 tabs / counts / empty-state /
список / reload-btn / filter=today default.
- AppLayout +2: бейдж скрыт при count=0 / показывает count при >0.
Pest 347/347 (без изменений — backend нетронут).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 12:41:41 +03:00 |
|
Дмитрий
|
768628d914
|
phase2(7-features): bulk-actions / new-deal / tenant-card / system-edit / webhook / smart-filters / impersonation-list
7-фичный auto-mode пакет согласно «карте что осталось» (после v1.54).
(1) Bulk-actions DealsView:
- dealsState reactive-копия MOCK_DEALS (deep-clone) для безопасного bulk-edit.
- Bulk-bar (sticky, теало-нуар, theme=dark) при selected.length > 0:
count + Сменить статус (v-menu × 14 lead_statuses) + Экспорт (snackbar) +
Удалить (v-dialog confirm) + ✕ clear.
- На production: smart status-transition с проверкой allowed-переходов;
soft-delete (архив 30 дней); реальный CSV/XLSX export через xlsx-lib.
(2) NewDealDialog (used in DealsView+KanbanView):
- 6 полей: name/phone/project (MOCK_PROJECTS) / manager (MOCK_MANAGERS) /
cost / status (default 'new' или presetStatus). Phone-валидация ≥10 цифр.
- emit('created', deal) → DealsView push в начало dealsState; KanbanView push
в правильную колонку по statusSlug + totalDeals++.
(3) AdminTenantDetailView (/admin/tenants/:code):
- 4 KPI cards (Баланс/runway / Тариф+MRR/мес / Лиды сегодня+неделя+месяц /
Средняя цена). 4 v-tabs: Финансы (balance-history) / Пользователи /
Проекты / Активность с event-кодами.
- Кнопка «Войти как клиент» (использует ImpersonationDialog из v1.54).
404-fallback. composables/mockTenantDetail.ts с expandTenantDetail.
- AdminTenantsView получил @click:row → router.push.
(4) Edit-flow AdminSystemView (audit-log + 2-step):
- Backend: SystemSetting + SaasAdminAuditLog Eloquent (append-only,
payload_before/after JSONB casts).
- AdminSystemSettingsController с GET (list) + PUT (update в DB::transaction
+ INSERT в saas_admin_audit_log; hash-chain trigger BEFORE INSERT
заполняет log_hash).
- Type-validation: int/decimal/bool/json. Reason ≥30 chars. No-op → 422.
- Frontend SystemSettingEditDialog — 3-step (edit → confirm с diff
before/after → done).
(5) Webhook receive endpoint (POST /api/webhook/{token}):
- WebhookReceiveController::receive. Token = tenants.webhook_token.
- 404 unknown / 422 bad payload / 202 success + dispatch ProcessWebhookJob.
- Stub-INSERT в webhook_log через DB::table обёрнут в DB::transaction +
SET LOCAL app.current_tenant_id для RLS.
- CSRF-исключение для api/webhook/* в bootstrap/app.php.
- На prod: + HMAC X-Webhook-Signature + per-token rate-limit.
(6) Smart-filters:
- DealsView: multi-select v-select Проект+Менеджер с auto availableProjects/
availableManagers computed.
- AdminTenantsView: filterStatuses (4 STATUS_OPTIONS) + filterTariffs
(computed availableTariffs).
- Кнопка «Сбросить» появляется только когда фильтры активны.
(7) AdminImpersonationView (/admin/impersonation):
- Backend +2 GET endpoints: /active (used_at != null AND session_ended_at
== null) + /recent (last 20 завершённых с duration_seconds через
abs(diffInSeconds) — Carbon signed по умолчанию).
- ImpersonationToken получил belongsTo(Tenant).
- Frontend view: 2 секции (Активные с end-кнопкой / Недавно завершённые
read-only) + refresh + onMounted load.
- Маршрут /admin/impersonation + 5-й nav-пункт «Impersonation» в AdminLayout.
Vitest +48 (всего 238/238 за 15.31 сек).
Pest +16 (всего 136/136 за 15.8 сек, 495 assertions).
PHPStan baseline регенерирован (0 errors после фикса nullsafe.neverNull).
Регресс: lint+type-check+format ✅; vite build 937 ms; Pint+PHPStan passed;
Pest 136/136. Реестр v1.54→v1.55, CLAUDE.md v1.45→v1.46.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 05:33:21 +03:00 |
|
Дмитрий
|
f65b2ca8d8
|
phase2(admin-views): AdminBilling/Incidents/System — реальные display-views
- AdminBillingView: 4 stats (MRR, Выручка, Просрочка, Возвраты) + v-data-table 7 колонок (Тенант с ИНН / Тариф / Баланс с error-color / пополнения / списания / MRR / Статус-chip) + поиск
- AdminIncidentsView: 3 stats + 5 фильтров статуса + v-list с incident_id (INC-YYYY-MMDD-NNNN) + severity/status/РКН-pending chips + дедлайн 24ч по 152-ФЗ
- AdminSystemView: read-only warning + поиск + v-list 7 system_settings (webhook_rate_limit, login_max_attempts, retention и т.д.) с type-chip и updated_at
- composables/mockAdmin.ts: AdminBillingTenantRow + AdminIncidentRow + AdminSystemSetting + mock-данные
- Router: /admin/{billing,incidents,system} → реальные views (не placeholder)
- Vitest +13 (179/179 за 11.98с)
- TODO: edit-flow для system_settings + backend /api/admin/* endpoints
- Регресс: lint+type+format OK; build 743ms; story:build 21/28 за 31.5с
- CLAUDE.md v1.42→v1.43, реестр v1.51→v1.52
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 04:17:17 +03:00 |
|
Дмитрий
|
c39d555e6f
|
phase2(recovery-code): POST /api/auth/2fa/recovery-use + UseRecoveryCodeView
- AuthController::useRecoveryCode перебирает unused codes через Hash::check, нормализация (lowercase + remove dash/space)
- UserRecoveryCode Eloquent (UPDATED_AT=null — schema без updated_at)
- Rate-limit auth:recovery:{pending_user_id}|{ip} (5/15мин)
- Returns recovery_codes_remaining для UI-warning'а (sessionStorage на frontend)
- UseRecoveryCodeView.vue → POST /api/auth/2fa/recovery-use, /recovery-use route, autocomplete=one-time-code
- TwoFactorView "резервный код" ссылка /recovery → /recovery-use
- Pest +6 RecoveryCodeTest (91/91 за 12.77с, 319 assertions)
- Vitest +6 (166/166 за 11.47с)
- TODO: #3 2FA setup wizard (после этого /recovery view получит реальный source данных)
- Регресс: lint+type+format OK; build 849ms; story:build 21/28 за 30.36с; Pint+Stan passed
- CLAUDE.md v1.38→v1.39, реестр v1.47→v1.48
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 03:43:58 +03:00 |
|
Дмитрий
|
9c488122a1
|
phase2(reset-password): POST /api/auth/reset-password + ResetPasswordView + DB timezone fix
- AuthController::resetPassword через Password::reset() (callback пишет password_hash)
- ResetPasswordRequest: token + email + password (min 10 по ТЗ §22.4.1) + confirmed
- Rate-limit auth:reset:{sha256(token)[0..16]}|{ip} (5/15мин)
- ResetPasswordView для deep-link /reset/:token?email=...; pre-fill email из query; success → redirect /login через 3 сек
- Vue Router /reset/:token (guestOnly); web.php /reset SPA-path
- DB FIX: config/database.php pgsql.timezone=UTC — без него PG TIMESTAMPTZ +03 терялся при Carbon::parse и tokenExpired ошибочно срабатывал
- Pest +6 ResetPasswordTest (85/85 за 11.50с, 291 assertions)
- Vitest +7 (160/160 за 11.02с)
- Регресс: lint+type+format OK; build 784ms; story:build 21/28 за 30.74с; Pint+Stan passed
- CLAUDE.md v1.37→v1.38, реестр v1.46→v1.47
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-09 03:36:27 +03:00 |
|
Дмитрий
|
59299d3c2b
|
phase2(auth-frontend): axios + Pinia + auth-store + auth-guards + form integration
- axios@^1.16 + pinia@^3.0 (--legacy-peer-deps).
- api/client.ts: axios с withCredentials+withXSRFToken (Sanctum SPA auto-XSRF).
ensureCsrfCookie() + extractValidationErrors/Message helpers.
- api/auth.ts: типизированные login/register/me/logout с AuthUser interface.
- stores/auth.ts: Pinia composition-store (user/loading/requires2fa +
isAuthenticated computed + login/register/fetchMe/logout actions).
logout() catch-swallow - UI всегда выходит локально.
- LoginView/RegisterView: useAuthStore интеграция, real POST через store,
errors из 422 на v-text-fields, redirect на /dashboard или /2fa,
:loading на btn'ах.
- Auth-guard в router.beforeEach: meta.requiresAuth на 10 routes
(6 app + 4 admin), meta.guestOnly на login/register/forgot. При первом
переходе fetchMe() restore-session. Unauth → /login?redirect=<original>.
- / redirect → /dashboard (auth-guard перехватит если не залогинен).
- Pinia в app.ts через app.use(createPinia()).
- cspell-words.txt: мокаем.
Vitest +10 (всего 139/139 за 10.11s):
- auth-store 7 (initial state + login success/reject + register + fetchMe
success/401 + logout swallow).
- router 5 переписан (login.guestOnly + 6 protected + admin layout +
3 error без auth + unauth /dashboard → /login?redirect).
- LoginView/RegisterView/router тесты получили createPinia в plugins.
- vi.mock api/auth в router+auth-store specs.
Регресс: lint+type+format OK; vitest 139/139; vite build (main app-chunk
105→153.64 KB +axios+pinia+auth gzipped 54.54 KB) 806ms; story:build 21/28
за 31.73s; Pest 61/61 за 5.86s.
CLAUDE.md v1.32->v1.33, реестр Открытых_вопросов v1.41->v1.42.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 19:59:43 +03:00 |
|
Дмитрий
|
da65cf4bf7
|
phase2(admin): AdminLayout + AdminTenantsView - админка SaaS (12/13 концептов)
- AdminLayout: отдельный sidebar теало-нуар с под-брендом ADMIN (red error
10px JBM uppercase) + 4 nav (Тенанты 142 / Биллинг / Инциденты 3 / Система) +
topbar с crumb «Админка → currentPage» + admin-user-chip с error-color avatar.
- AdminTenantsView (/admin/tenants): page-head + 5-stats + Экспорт +
search/Статус/Тариф фильтры + v-data-table 7 колонок (Тенант с двухстрочным
name+inn / Статус-chip 4 цвета / Тариф / Баланс ₽ с error-color при <0 /
Желаем×факт / MRR с «—» / Активность).
- mockTenants.ts соответствует schema v8.7 §3: 4 статуса × 5 тарифов, 7 mock
с разнообразием (active/trial/overdue/suspended) + AdminStats (142/128/9/5/
1 248 600 ₽).
- AdminPlaceholderView универсальный для Биллинг/Инциденты/Система с
описаниями ссылающимися на schema v8.7 (incidents_log §9 / system_settings §10).
- AppShell расширен meta.layout='admin'. Router: /admin redirect на /tenants +
4 admin-route'а с lazy-imports. Web.php fallback покрывает /admin/*.
- cspell-words.txt: Екб.
Vitest +11 (всего 129/129 за 10.02s):
- заголовок + 5 stats (regex nbsp в 1 248 600 ₽) + 7 columns + 7 rows +
Окна Москва ИНН + overdue −1 200 + trial 4 дня + suspended + search filter
«Натяжные» → 1 row + Экспорт/Статус/Тариф кнопки.
Регресс: lint+type+format OK; vitest 129/129; vite build (admin views
в lazy-chunks; main 104.99 KB); story:build 21/28 за 30.32s; Pest 48/48 за 4.89s.
CLAUDE.md v1.30->v1.31, реестр Открытых_вопросов v1.39->v1.40.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 19:23:28 +03:00 |
|
Дмитрий
|
034657788d
|
phase2(errors): ErrorView 404/403/500 + Laravel fallback
- ErrorView универсальный с конфигурацией через route.meta.errorCode
(404/403/500). По v8_errors.html: full-bleed теало-нуар bg, top-brand,
err-code 96px JBM с accent на средней цифре, title/desc, 2 actions,
опциональные status-list (500) и err-id с copy-btn (403/500).
- AppShell: meta.layout='error' → RouterView напрямую (ErrorView сам
предоставляет v-app).
- Router: /403, /500, catch-all /:pathMatch(.*)* → ErrorView с meta.errorCode.
- web.php: явные Route::view + Route::fallback (срабатывает после Pest
runtime-routes, не ломает SetTenantContextTest).
- cspell-words.txt: резолвится, роуты.
Vitest +8 (всего 118/118 за 9.39s):
- 404 default + 403 с REQ-ID + 500 с INC-ID + status-list (API/Telegram/YooKassa) +
404 actions (На дашборд + Назад) + 403 mailto-link + 500 status-link +
brand-блок + 404 НЕ содержит REQ/INC/status-list (regression-guard).
- stubs:{VApp/VMain} как passthrough — обходим Vuetify layout-injection в jsdom.
Регресс: lint+type+format OK; vitest 118/118; vite build (ErrorView lazy-chunk;
main app-chunk 101.01KB упал на 7KB благодаря shared chunk'ам); story:build
19/26 за 30.96s; Pest 48/48 за 4.88s (fallback не сломал runtime-routes).
CLAUDE.md v1.29->v1.30, реестр Открытых_вопросов v1.38->v1.39.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 19:11:09 +03:00 |
|
Дмитрий
|
4de39e70b2
|
phase2(reports): ReportsView - асинхронная генерация отчётов с очередью
- ReportsView (/reports): form-card (Запросить) + jobs-list panel.
Form: 4 type-cards radio-grid (Сделки/Менеджеры/Источники/Биллинг) +
date-range + Проект/Менеджер v-select + 4 fmt-кнопки (CSV/XLSX/JSON/PDF) +
quota-banner alert (CTO-7: 2/3 одновременных + CTO-6: 3 попытки/7 дней) +
Запустить/Сброс.
- Jobs-list: 5 mock-rows × 4 статуса (done/running/queued/failed) с icon +
meta JBM (FORMAT · size · rows · timeText) + status-chip + actions
(Скачать done / Повторить failed && attempt<3 / Отменить queued /
Удалить done|failed). v-progress-linear для running 62%.
- composables/mockReports.ts: type unions (4×4×4) + 5 mock-jobs + MOCK_QUOTA
(CTO-6/7 значения).
- Маршрут /reports (meta.layout=app, lazy-import) в router + web.php.
Vitest +12 (всего 110/110 за 9.38s):
- заголовок + page-stats + 4 type-cards + дефолт active + 4 формата +
quota-banner («2 из 3» / «3 попыток retry» / «7 дней») + 5 job-rows +
done-«Готов»+Скачать-aria + running-«62%»+progressbar role + queued-Отменить +
failed-«Ошибка»+«S3 timeout»+Повторить-aria + клик-переключение active.
Регресс: lint+type+format OK; vitest 110/110; vite build (ReportsView lazy-chunk;
main 108.19 KB); story:build 18/25 за 30.77s; Pest 48/48 за 4.58s.
CLAUDE.md v1.28->v1.29, реестр Открытых_вопросов v1.37->v1.38.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 19:01:10 +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 |
|
Дмитрий
|
c8012896e3
|
phase2(billing): BillingView - финансовый экран биллинга и тарифов
- BillingView (/billing): page-head со stats (кошелёк/лиды/runway-дни) + pending
banner v-alert info («1 платёж в обработке через ЮKassa, auto-cancel 30 мин»)
+ 3 wallet-cards (Кошелёк ₽ primary card теало-нуар + LIVE; Баланс лидов
ГЦК; Тариф «Команда» 990₽/мес + 3 фичи) + transactions panel (4 tabs +
v-data-table 5 колонок: Дата/Операция/ID/Статус-chip/Сумма ± JBM tnum) +
invoices list (PDF + 1С 8.3 XML).
- composables/mockBilling.ts соответствует схеме v8.7 §4.4-4.5: 8 mock
транзакций (types: topup/lead_charge/refund/tariff_charge; statuses:
pending/completed/rejected) + 4 invoices (pdf/xml_1c83) + pending payment.
- Маршрут /billing (meta.layout=app) в router + web.php.
Format helpers: «+ N ₽» / «− N ₽» / «— 0 ₽» rejected; Intl.NumberFormat ru-RU.
Vitest +11 (всего 90/90 за 7.96s):
- заголовок + page-stats nbsp regex + pending banner + 3 wallet-cards + 3 фичи
тарифа + 4 tabs + дефолт «Все» 8 строк + format «+/−» + rejected «— 0 ₽» +
4 invoice rows + PDF/1С 8.3 XML labels.
Регресс: lint+type+format OK; vitest 90/90; vite build (BillingView lazy-chunk;
VDataTable вынесен в общий chunk 79.84KB - shared с DealsView); story:build
16/23 за 32.16s; Pest 48/48 за 4.89s.
CLAUDE.md v1.26->v1.27, реестр Открытых_вопросов v1.35->v1.36.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 18:39:49 +03:00 |
|
Дмитрий
|
d39934c8d9
|
phase2(kanban): KanbanView - 14 колонок по lead_statuses (БЕЗ DnD)
- KanbanCard: компактная карточка (name/phone/project/cost/manager-avatar),
emit('open',id) на click для будущего DealDetailDrawer.
- KanbanColumn: header с border-top по colorHex статуса (--accent CSS-var) +
name+count+total ₽; body с v-for карточек + empty-state «пусто».
- KanbanView: orchestrator, 14 колонок (по LEAD_STATUSES) с группировкой
MOCK_DEALS по statusSlug, horizontal-scroll с custom scrollbar.
- Маршрут /kanban (meta.layout=app) в router + web.php.
- .gitleaks.toml: tests/Frontend/*.spec.ts в allowlist (assertion на mock-телефоны).
- cspell-words.txt: инлайн, vueuse.
DnD НЕ реализован на MVP - отдельный коммит после выбора библиотеки
(vue-draggable-next или @vueuse/integrations/useSortable).
Vitest +14 (всего 70/70 за 7.37s):
- KanbanCard 3 (data + initials + emit open)
- KanbanColumn 5 (header + total + empty + accent CSS-var case-insensitive +
проброс openDeal)
- KanbanView 6 (заголовок + 14 columns + правильные status'ы + stats + кнопка +
DnD-предупреждение)
Регресс: lint+type+format OK; vitest 70/70; vite build (KanbanView lazy-chunk);
story:build 14/20 за 31.17s; Pest 48/48 за 5.06s.
CLAUDE.md v1.23->v1.24, реестр Открытых_вопросов v1.32->v1.33.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 17:56:59 +03:00 |
|
Дмитрий
|
a51a94830c
|
phase2(deals): DealsView - центральный экран CRM (список сделок)
- DealsView (/deals): page-head со stats (всего/в работе/ждут оплату) +
Экспорт/Новая сделка кнопки. filter-bar с 5-tab chiprow (Все/Активные/
Ждут оплату/Закрытые/Невалидные) + поиск по name/phone/project.
v-data-table с 6 колонками: Лид (avatar+name+phone), Статус (tonal-chip
с colorHex из lead_statuses), Проект, Менеджер, Стоимость (Intl.NumberFormat
ru-RU JBM tnum), Время (formatRelative мин/ч/д назад). show-select для
будущих bulk-actions. Empty-state.
- composables/mockDeals.ts: 12 mock-сделок + DEALS_TABS (5 срезов с slug[]).
- Маршрут /deals (meta.layout=app) в router + web.php.
- .gitleaks.toml: mockDeals.ts в allowlist (фиктивные имена/телефоны).
Vue regex quirk: ESLint no-irregular-whitespace в regex с literal nbsp -
\s в JS уже matches U+00A0/U+202F из Intl.NumberFormat, использовать \s+.
Vitest +8 (всего 56/56 за 5.66s): заголовок + page-stats + 5 tabs +
дефолт active-фильтр (5/12 строк) + кнопки + 6 колонок + format «2 400 ₽» +
format «7 мин назад».
Регресс: lint+type+format OK; vitest 56/56; vite build (DealsView lazy-chunk
87.54KB - v-data-table крупный, но грузится только на /deals); story:build
11/15 за 31.93s; Pest 48/48 за 4.96s.
CLAUDE.md v1.22->v1.23, реестр Открытых_вопросов v1.31->v1.32.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 17:45:25 +03:00 |
|
Дмитрий
|
1e233a70c8
|
phase2(dashboard): AppLayout + DashboardView - default-layout приложения
- AppLayout: v-navigation-drawer (теало-нуар sidebar 240px) + brand-block
+ nav-tree из 8 пунктов в 3 группах (Работа/Финансы/Команда), v-app-bar
с crumb «Рабочая область → currentPage» + search ⌘K + bell + user-chip.
Mobile (md<): drawer toggleable.
- DashboardView: page-head «Доброе утро, Иван» + page-meta + range-toggle
4 опции (Сегодня/7д/30д/Период). KPI-row из 4 cards: 3 outlined (получено
лидов/конверсия/активные проекты) + 1 hero balance с runway-bar 4/7
заполненных сегментов teal #32C8A9.
- AppShell упрощён до layout-mapper (route.meta.layout 'app'/'auth').
- Маршрут /dashboard (meta.layout='app') в router + web.php.
- histoire.setup расширен 8 app-stub-маршрутами для AppLayout.
- Vitest +11 тестов: AppLayout 6 (brand+3 группы+8 пунктов+счётчики+crumb),
DashboardView 5, AppShell.spec.ts переписан под layout-mapper.
- cspell-words.txt: JBM.
Регресс: lint+type-check+format OK; vitest 35/35 за 4.92s; vite build
DashboardView lazy-chunk 14.9KB; story:build 8/8 за 28.97s; Pest 48/48 за 4.88s.
CLAUDE.md v1.20->v1.21, реестр Открытых_вопросов v1.29->v1.30.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 17:21:19 +03:00 |
|
Дмитрий
|
19096552b4
|
phase2(auth): закрыты 4 оставшихся auth-экрана из v8_login.html
- RegisterView: email + password (strength-meter 0..4) + 2 click-wrap'а
(оферта + ПДн). 3-й «маркетинг» из handoff НЕ реализован (расхождение
#2 реестра v1.13 - handoff противоречит ТЗ §1.5/§4.1).
- TwoFactorView: 6 input-cell с auto-focus вперёд при вводе цифры,
Backspace назад при empty, paste 6 цифр заполняет все.
- ForgotPasswordView: email + alert «5 попыток / 15 минут» по ТЗ §1.7.
- RecoveryCodesView: 8 кодов в 2-column grid + Скачать .txt (Blob/URL.createObjectURL)
+ Копировать (navigator.clipboard) + warning о невозможности повторного просмотра.
Router: 4 новых маршрута (/register, /2fa, /forgot, /recovery), все
meta.layout='auth', lazy-imports.
Vitest +14 тестов (всего 24/24 за 3.29s):
- RegisterView 4 (вкл. assertion на отсутствие маркетингового click-wrap)
- TwoFactorView 3, ForgotPasswordView 3, RecoveryCodesView 4
Stories +4 (Histoire 6/6 за 29.17s).
Регресс: lint+type-check+format OK; vitest 24/24; vite build 5 lazy-chunks
для views + Vuetify в отдельные chunks (app chunk 198KB→78KB); Pest 48/48 за 4.85s.
CLAUDE.md v1.19→v1.20, реестр Открытых_вопросов v1.28→v1.29.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 17:09:56 +03:00 |
|
Дмитрий
|
e909a95a8d
|
phase2(login): vue-router 4 + AuthLayout + LoginView - первый реальный экран
- vue-router@^4.6.4 (--legacy-peer-deps из-за Histoire vs Vite 8 peerDep).
- resources/js/router/index.ts: createWebHistory + lazy-imports + meta.layout.
Маршрут / -> /login, /login -> LoginView (meta.layout=auth).
- resources/js/layouts/AuthLayout.vue: двухпанельный (brand-pane тёмный с
radial-gradient акцентами + form-pane warm ivory). На mobile brand-pane скрыт.
- resources/js/views/auth/LoginView.vue: форма Vuetify по v8_login.html
секция #form-login - email/password (autocomplete + eye-icon), primary submit,
Yandex 360 SSO, RouterLink на /register и /forgot.
- AppShell.vue: layout-mapper по route.meta.layout (default/auth).
- routes/web.php: явные Route::view для 6 SPA-путей (НЕ catch-all - он перехватывал
/_test/* в Pest beforeEach и валил 5 SetTenantContextTest).
- Vitest: +LoginView.spec.ts (5), +router.spec.ts (2), AppShell.spec.ts переписан (3).
Vitest 10/10 за 3.01s.
- LoginView.story.vue для Histoire. Setup расширен memory-router'ом.
- cspell-words.txt: рендерят, коммиты, Лидерру.
- Регресс: lint:vue OK, type-check OK, format:check OK, vitest 10/10,
vite build 212 модулей за 383ms (LoginView lazy-chunk 43.5KB JS / 51.7KB CSS),
story:build 2/2 за 29.94s, Pest 48/48 за 4.86s.
CLAUDE.md v1.18->v1.19, реестр Открытых_вопросов v1.27->v1.28.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-05-08 16:59:00 +03:00 |
|