Дмитрий
c5c0e76950
test(coverage): close F-COV-01/02/03 — ReminderDialog + AdminLayout + api/admin
...
Closes Audit #2+#3 P2 carryforward triplet (low-coverage files at risk
of silent regression).
Coverage results (Vitest --coverage --coverage.include per-file):
| File | Stmts before | Stmts now | Δ |
|---|---|---|---|
| ReminderDialog.vue | 0% | 95.38% | +95 pp |
| AdminLayout.vue | 9.09% | 95.45% | +86 pp |
| api/admin.ts | 11.53% | 100% | +88 pp |
Branches/Funcs deltas (subagent reports):
- ReminderDialog: Branch 0→97.56%, Funcs 0→85.71%, Lines 0→96.61%
- AdminLayout: Branch 0→90%, Funcs 0→90%, Lines 9.09→94.73%
- api/admin: Branch 0→100%, Funcs 27.27→100%, Lines 11.53→100%
Approach: TDD via @vue/test-utils + Vuetify global plugin + vi.mock for
store/api. Three parallel subagents (general-purpose), each focused on
single target — no production code changes, only test infrastructure.
Coverage areas:
- ReminderDialog (19 specs): rendering, watch(dialogOpen) populate/reset,
submit create-mode happy + 3 errors, submit edit-mode happy + 1 error,
cancel, common validation paths
- AdminLayout (16 specs): brand block, 5 nav items, count badges (142/3),
breadcrumb per route (5 cases + fallback), userInitials computed (4
cases incl. fallback), userShortName (4 cases), handleLogout call-order,
active state, aria-label
- api/admin (18 specs): 11 exported functions × happy-path; 2 encodeURI
edge cases; 4 ensureCsrfCookie call-order verifications via
invocationCallOrder; 2 error-propagation tests
Verification (full sweep after merge):
- Vitest: 91 files / 736 passed / 3 skipped / 0 failed (+3 files, +53 specs
from Audit #3 baseline 88/683/3sk)
- Pest --parallel: 742/739/3sk/0 (identical to baseline, 0 regressions)
- Vite build: 2.03s
- vue-tsc: 0 errors
- ESLint: 0 errors
Plan: docs/superpowers/plans/2026-05-14-audit3-deferred-fixes.md Task 3.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-14 08:37:26 +03:00
Дмитрий
e280edd431
style(frontend): apply prettier --write — fix formatting drift
...
4 files reformatted (import list expansion, line-length wrapping).
Vitest 88/683+3sk green.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-13 13:30:51 +03:00
Дмитрий
f2627e4d3e
test(router): Q.DEFER.003 sub-C — 5 integration tests for guard branches
...
Coverage uplift router/index.ts от 33% Stmts / 7% Funcs к ~85% Funcs:
- authenticated /login (guestOnly) → /dashboard redirect
- authenticated /dashboard passes requiresAuth
- /no-such-path → 404 catch-all
- /admin → /admin/tenants redirect
- /reset/:token param exposure
Refactored vi.mock me() для conditional resolve/reject per test.
2026-05-13 01:55:06 +03:00
Дмитрий
c09bff3799
test(security): Q.DEFER.003 sub-B — TwoFactorCard 9 own-spec tests
...
Coverage uplift от 28% to 80%+: enable button visibility / disable button
visibility / chip status / setup wizard openSetup→confirm→codes / invalid
code error / disable flow valid+invalid password / closeSetup state reset.
vi.mock authApi для 3 endpoint'ов (init/confirm/disable).
2026-05-13 01:46:30 +03:00
Дмитрий
918c962b26
test(security): Q.DEFER.003 sub-B — RecoveryCodesCard 6 own-spec tests
...
Coverage uplift от 28% to 70%+ (auth-gated visibility / dialog flow /
confirmRegen success+error / closeRegen reset). vi.mock authApi
для изоляции; VDialog stub'аем для DOM unit-test (избегаем teleport).
2026-05-13 01:41:27 +03:00
Дмитрий
4c6d593776
test(security): Q.DEFER.003 sub-B — ChangePasswordCard 3 own-spec tests
...
Placeholder card (17 lines, static UI) — add minimal coverage for heading,
last-change hint, and button rendering. Closes coverage debt от 0% Stmts.
2026-05-13 01:36:22 +03:00
Дмитрий
c8005e0cfc
fix(a11y): Q.DEFER.004 sub-B — AdminSupplierPricesView 9 inputs aria-label
...
3 supplier rows × 3 form controls (cost_rub v-text-field +
quality_score v-text-field + is_active v-switch) = 9 nodes без label —
axe-core критичная label violation.
Fix: :aria-label='${field} для ${supplier.name}' (e.g. 'Cost (₽) для B1 — Сайты и Звонки').
Test coverage: AdminSupplierPricesView.spec.ts 4-й spec проверяет все 9 ожидаемых
aria-label через DOM query.
2026-05-13 00:35:05 +03:00
Дмитрий
d9fc3d92e4
fix(a11y): Q.DEFER.004 sub-A — DealsTable show-select bulk-checkbox aria-label
...
VDataTable show-select prop генерировал unlabeled checkbox per row + select-all
header — axe-core критичная label violation (6 nodes на demo seed).
Override через Vuetify 3.12 typed slots:
- header.data-table-select → aria-label='Выбрать все сделки'
- item.data-table-select → aria-label='Выбрать сделку «{{name}}»' (per row)
Test coverage: tests/Frontend/DealsTable.spec.ts (2 specs).
2026-05-13 00:28:39 +03:00
Дмитрий
95f5f94a6b
test(api): Q.DEFER.003 sub-A — 43 unit tests for api/*.ts layer
...
User chose (A) api/* unit tests first (highest ROI per blocked.md). 5 new
spec files covering auth/deals/notifications/reminders/reports api modules.
- auth-api.spec.ts (13 tests): login/register/me/logout/verifyTwoFactor/
useRecoveryCode/twoFactorInit/Confirm/Disable/RegenerateRecoveryCodes/
forgotPassword/resetPassword/updateNotificationPreferences
- deals-api.spec.ts (12 tests): createDeal/bulkDelete/bulkRestore/update/
transition/exportCSV/exportXLSX/getDeal/listDeals×2/listManagers/
listProjects
- notifications-api.spec.ts (6 tests): listNotifications×3 (unreadOnly
variants)/markRead/markAllRead/delete
- reminders-api.spec.ts (6 tests): listReminders×2/create/update/complete/
delete
- reports-api.spec.ts (6 tests): listReportJobs×2/create/retry/cancel/delete
Approach: vi.mock('../../resources/js/api/client') replaces apiClient with
{get,post,patch,delete} mocks + ensureCsrfCookie mock. Each test verifies:
(1) correct HTTP method, (2) correct URL, (3) correct params/body
(camelCase→snake_case mapping for query params), (4) data unwrap from
wrapper objects ({user}/{deal}/{job}/{reminder}/{managers}/{projects}),
(5) ensureCsrfCookie called for mutating endpoints.
Vitest delta: 614 → 657 passed (+43 / 0 failed); 79 → 84 files (+5).
3 skipped unchanged. Q.DEFER.003 sub-B (security cards) + sub-C (router
guards) remain deferred — sub-A api/* was highest ROI per blocked.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 22:14:51 +03:00
Дмитрий
143cc458c1
fix(a11y): Q.DEFER.002 sub-B — 12 patterns fixed across 16 auth views
...
Q.DEFER.002 sub-B closure: manual Pa11y audit-pass via Playwright MCP login +
axe-core CDN inject on 16 auth-required views. Found ~13 unique violation
patterns, 12 fixed, 3 deferred to Q.DEFER.004.
ROOT CAUSE found: AdminLayout `<v-navigation-drawer color="secondary"
theme="dark">` resolved to Vuetify default-dark `secondary=#54b6b2` (Teal
mid) instead of liderraForest `#012019` теало-нуар. Switching to direct hex
preserves design intent + restores white-text contrast across all 8 admin
views (~50 nodes color-contrast violations cleared).
Patterns fixed:
1. AdminLayout sidebar palette (8 admin views):
- color="secondary" → color="#012019 " (root cause)
- .brand-sub red #b94837 → #e06155 (3.41 → 5.08)
- .nav-count gray #7a8c87 → #8a9c95 (4.26 → 5.34)
- <v-list nav> + role="navigation" + aria-label (aria-required-children
fix: <v-list role=list> had [role=link] children — undefined для list)
2. DashboardBalance .runway-bar — role="img" (aria-prohibited-attr fix)
3. DashboardKpiRow .delta-up — #2e8b57 → #1b6e3b (4.27 → 6.25)
4. TransactionsTable .tx-amount-up — #2e8b57 → #1b6e3b (same fix)
5. RemindersList .empty-hint — #9a9690 → #6b6356 (2.98 → 5.74; +liderra-muted alignment)
6. KanbanView .kanban-board — tabindex="0" role="region" aria-label
(scrollable-region-focusable fix)
7. ProjectCard:
- .v-progress-linear + :aria-label="Прогресс дневной нормы: N%"
- icon menu :aria-label="Меню действий проекта «...»"
- bulk-select .card-check input :aria-label="Выбрать проект «...»"
8. useStatusPill in_progress #3F7C95 → #2A5A6E (4.07 → 6.11);
useStatusPill.spec.ts sync
9. ProjectsView toolbar select-all input aria-label
10. AdminTenants impersonate v-btn aria-label
11. Global app.css:
`.v-messages, .v-field-label { --v-medium-emphasis-opacity: 0.7; }`
Vuetify default ~0.52 → rendered #7a7a7a/#767471 fails 4.20-4.29:1;
0.7 → rendered ≈#595959 → 7.9:1+ passes WCAG AA.
Re-verified post-fix via axe-core on all affected views: all clean except
DEV-only `.dev-index-num` chip (tree-shaked в prod, not a real violation).
Vitest verified post-fix: 79 files / 614 passed / 3 skipped / 0 failed
(baseline preserved).
3 patterns deferred to Q.DEFER.004:
- DealsTable VDataTable show-select bulk-checkboxes (6 nodes) — Vuetify
slot rewrite needed
- AdminSupplierPrices 9 form inputs — v-text-field/v-switch label props
- Vuetify v-tooltip eager-mount aria-tooltip-name — library-level cosmetic
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 22:09:48 +03:00
Дмитрий
245b76ec43
test(frontend): fix 17 ESLint errors + TwoFactorView router stub
...
ESLint emitted 17 errors in tests/Frontend/* (production code clean):
- 13× @typescript-eslint/no-explicit-any in axios mock casts
(BulkActionsBar, ProjectsView, projectsStore specs)
- 3× vitest/no-disabled-tests rule-not-found
(eslint-plugin-vitest not registered; inline-disable comments stale)
- 1× @typescript-eslint/no-unused-vars on imported beforeEach
Plus Phase 5 audit finding: TwoFactorView.spec.ts test router was
missing /recovery-use stub → Vue Router warn on every TwoFactorView mount.
Changes:
- BulkActionsBar.spec.ts, ProjectsView.spec.ts, projectsStore.spec.ts:
replace `as any` with `as unknown as ReturnType<typeof vi.fn>` on
axios method mocks; one case used `as unknown as { regionsOpen: bool }`
for vm shape.
- NewProjectDialog.spec.ts, ProjectsView.spec.ts: remove stale
`// eslint-disable-next-line vitest/no-disabled-tests` comments
(it.skip() lines kept).
- ProjectsView.toolbar.spec.ts: drop unused `beforeEach` from import.
- TwoFactorView.spec.ts: add `/recovery-use` route stub.
Verification:
- npx eslint --max-warnings=0 → exit 0 (was 17 errors).
- npx vitest run on affected specs → 24/27 passed + 3 skipped (was same).
- TwoFactorView spec → 3/3 passed, no Vue Router warn.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 20:23:51 +03:00
Дмитрий
55a9d3fe00
fix(types): unify Project interface + NavItem.countKey + drop legacy Record
...
vue-tsc was emitting 9 errors from two issues:
1. ProjectCard.vue had a local `interface Project` missing region_mask /
region_mode / delivery_days_mask, while stores/projectsStore.ts
exported the canonical one with those fields. ProjectsView.vue passed
the canonical Project to ProjectCard handler signatures which expected
the local incomplete one → 5× TS2322.
2. EditProjectDialog passed `project: Project | Record<string, unknown>`
to NewProjectDialog which expected `Record<string, unknown> | null`.
Project lacks an index signature → TS2322.
3. AppSidebar.vue template referenced `item.countKey` not declared in
NavItem interface → 2× TS2339.
Changes:
- ProjectCard.vue: drop local Project, import from projectsStore.
- NewProjectDialog.vue: project prop type → Project | null (was Record).
Drop `as { id: number }` cast on PATCH URL.
- EditProjectDialog.vue: project prop type → Project | null.
- AppSidebar.vue: add `countKey?: string` to NavItem.
- projectsStore.ts: make region_mask/region_mode/delivery_days_mask
optional (backward-compat for mock fixtures; production rows always
populate them by schema).
- Test/story fixtures expanded with delivered_today/is_active/archived_at/
sync_status to match strict Project shape.
Verification:
- npx vue-tsc --noEmit → 0 errors (was 9).
- npx vitest run on 5 affected specs → 16/16 passed + 2 skipped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 20:15:26 +03:00
Дмитрий
84530d55bf
test(projects): fix ProjectCard change-trigger target
...
Pre-existing failing test from commit c9ee8d8 — data-testid lives on
<label>, but @change handler sits on <input> inside it. jsdom does not
bubble change-event from label to input via @vue/test-utils trigger.
Use child-input selector to fire the event on the right node.
Baseline после fix: 614 passed / 3 skipped / 0 failed (vs 613 / 3 / 1).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 17:36:33 +03:00
Дмитрий
df92ac02ff
feat(projects-bulk): wire 3 new dialogs into BulkActionsBar
...
Add RegionsBulkDialog / DaysBulkDialog / LimitBulkDialog to
BulkActionsBar with open-state refs (regionsOpen/daysOpen/limitOpen),
runBulk helper via store.bulkUpdate, and flex-wrap layout.
Update spec: fix existing tests (bulkAction → bulkUpdate), add 3 new
dialog-wiring tests (7/7 pass; full suite 614+3skipped/0failed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 15:23:29 +03:00
Дмитрий
4b6ab8f113
feat(projects-bulk): LimitBulkDialog delta or replace mode
...
Delta mode combines Add/Remove numeric inputs into a single signed delta;
Replace mode switches to an absolute value input via v-checkbox toggle.
5/5 Vitest pass; full suite 611 passed + 3 skipped.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 15:20:18 +03:00
Дмитрий
4c470813b4
feat(projects-bulk): DaysBulkDialog Add/Remove (7 weekday bitmask)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 15:17:16 +03:00
Дмитрий
3b254fb56f
feat(projects-bulk): RegionsBulkDialog Add/Remove (8 ФО bitmask)
2026-05-12 15:14:18 +03:00
Дмитрий
95bba384a1
feat(projects-bulk): select-all toolbar with counter and indeterminate state
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 15:11:21 +03:00
Дмитрий
a46e63bdd3
feat(projects-bulk): store selectAllByFilter + bulkUpdate with scope discriminator
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 15:08:08 +03:00
Дмитрий
5c8ad2738a
feat(layout): dark topbar + sidebar cleanup + DevIndexBadge moved below
...
Sidebar: убраны Менеджеры/Напоминания; Работа в порядке
Проекты/Сделки/Канбан/Дашборд; Команда — только Настройки;
снят useRemindersStore (был только под reminders badge).
Topbar: тёмный фон linear-gradient(noir → #04261E) совпадающий
с sidebar #1271 ; убран breadcrumb «Рабочая область»;
v-toolbar__content padding-left:240 (не уходит под sidebar).
DevIndexBadge: top:64 (ниже топбара, не перекрывает user-chip).
Vitest AppLayout 15/15 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 14:32:03 +03:00
Дмитрий
d238ca5f4a
feat(dev-indices): overlay Alt-keys (up/down) + Alt+Shift+I toggle + mini-badges
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 12:05:53 +03:00
Дмитрий
d8c33b4cd6
feat(dev-indices): DevIndexOverlay (hover badge + click-copy + Esc + AppShell mount)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 12:02:38 +03:00
Дмитрий
901530ae41
feat(dev-indices): useDevIndices composable (state + DOM walk)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-05-12 11:57:35 +03:00
Дмитрий
e2669270f3
feat(redesign): Task 17 — ProjectCard tokens (hover lift + JetBrains Mono numerics)
2026-05-12 10:22:36 +03:00
Дмитрий
22e6bdf8b8
feat(redesign): Task 16 — KanbanView StatusPill + hover lift (motion #4 )
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-12 10:19:21 +03:00
Дмитрий
2f46a3e5ec
feat(redesign): Task 15 — DealsView filterbar + density + StatusPill + hover lift (motion #2,#4)
2026-05-12 10:13:19 +03:00
Дмитрий
35662f7b56
feat(redesign): Task 14 — DashboardView KPI count-up (motion #1 ) + live pulse
2026-05-12 10:06:08 +03:00
Дмитрий
a09434eca0
feat(redesign): Task 13 — page transition wiring (Vue Transition + CSS fadeup, motion #6 )
2026-05-12 09:59:22 +03:00
Дмитрий
3f956224bd
feat(redesign): Task 12 — AppSidebar двухтоновый shell + ⌘K stub + active marker (motion #7 )
2026-05-12 09:54:54 +03:00
Дмитрий
2707ff64ab
feat(redesign): Task 11 — DensityToggle component (compact/comfortable + persist)
2026-05-12 09:49:37 +03:00
Дмитрий
0b2ec5b802
feat(redesign): Task 10 — FilterChip component (label + count + active states)
2026-05-12 09:47:02 +03:00
Дмитрий
52cc64c9e6
feat(redesign): Task 9 — Kbd component (⌘K, Esc badges; light+dark variants)
2026-05-12 09:45:22 +03:00
Дмитрий
ff3bc8bcc1
feat(redesign): Task 8 — StatusPill component + 14-variant Histoire story
2026-05-12 09:43:02 +03:00
Дмитрий
7322c7f33a
feat(redesign): Task 7 — useDensity composable (localStorage + rowHeight)
2026-05-12 09:37:43 +03:00
Дмитрий
eda13679b4
feat(redesign): Task 6 — useCountUp composable (RAF tween + prefers-reduced-motion)
2026-05-12 09:34:55 +03:00
Дмитрий
cdd1b5efdb
feat(redesign): Task 5 — useStatusPill composable (14 slugs из db/schema.sql)
2026-05-12 09:29:53 +03:00
Дмитрий
ea4570dafe
feat(redesign): Task 4 — extend Vuetify theme (12 colors) + global component defaults
2026-05-12 09:27:22 +03:00
Дмитрий
b858df569e
feat(redesign): Task 3 — motion.css (5 keyframes + reduced-motion wrapper + utilities)
2026-05-12 09:23:50 +03:00
Дмитрий
baf27bd02d
feat(redesign): Task 2 — typography.css (Inter variable + JetBrains Mono + tnum)
2026-05-12 09:20:13 +03:00
Дмитрий
688d9cfb24
feat(redesign): Task 1 — tokens.css (12 colors + spacing + radii + shadows)
2026-05-12 09:15:29 +03:00
Дмитрий
76b1562593
feat(frontend): Plan 5 Task 11 — polling integration (setTimeout-recursion + backoff)
2026-05-11 19:44:56 +03:00
Дмитрий
1c3989a6df
feat(frontend): Plan 5 Task 10 — EditProjectDialog wrapper + BulkActionsBar + 7 tests
2026-05-11 19:41:53 +03:00
Дмитрий
92082606e3
feat(frontend): Plan 5 Task 8 — ProjectsView + projectsStore (no polling) + 9 tests
2026-05-11 19:38:59 +03:00
Дмитрий
8bc7838f0c
feat(frontend): Plan 5 Task 9 — NewProjectDialog (3 tabs Site/Call/SMS) + story
2026-05-11 19:31:26 +03:00
Дмитрий
c9ee8d866e
feat(frontend): Plan 5 Task 7 — router + nav + regions + ProjectCard + story
2026-05-11 19:31:23 +03:00
Дмитрий
174dbae808
feat(billing): Plan 4 Task 11 — TenantChargesController + ChargesTab + CSV export
...
Backend TenantChargesController:
- GET /api/billing/charges — paginated list, filters period (current_month / last_month / 90d) + charge_source.
- POST /api/billing/charges/export — StreamedResponse CSV (BOM + UTF-8) с chunkById(500).
- auth:sanctum + tenant middleware — RLS изолирует tenant_id.
- 6 Pest integration tests (RLS isolation + filters + pagination + CSV export).
Frontend ChargesTab.vue:
- v-data-table-server с paginated load + period/charge_source filters.
- CSV-download через blob → createObjectURL.
- Forest-palette + JetBrains Mono tnum.
BillingView.vue — добавлен tab «Списания» с импортом ChargesTab.
ChargesTab.story.vue + 4 Vitest tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-11 11:51:13 +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
Дмитрий
cab1f87efd
phase2(admin-tenant-detail-frontend): replace mock на real API в AdminTenantDetailView
...
- api/admin.ts +getAdminTenantDetail(subdomain) + 5 типов (ApiTenantUser/Project/
BalanceTx/ActivityEvent/Metrics + AdminTenantDetailResponse).
- composables/adminTenantDetailMapper.ts: mapAdminTenantDetail (API → mockTenantDetail
format). code=subdomain, deriveStatus (trial/overdue/suspended), deriveTariff
(Trial fallback), users (fullName из first+last||email, role='manager' хардкод —
schema users role нет, расширим в Post-MVP), projects (slug=tag), balanceHistory
(id префикс TX-, type-mapping для chargeback_*/trial_bonus/historical_import →
ближайший UI-эквивалент), activity (actor=actor_email||system, summary из
context.from→to), activitySinceText (relative time из last_activity_at).
- AdminTenantDetailView.vue: replace mock-lookup на async loadTenant + 3 ветки
template (loading / notFound / fetchError) + watch(code) для реактивной
навигации. inn/contact_phone/legal_address скрываются через v-if (нет в schema).
- AdminTenantDetailView.spec.ts переписан с MOCK на vi.mock('api/admin'):
13 тестов (вызов API с subdomain / organization_name+tariff / 4 KPI / KPI Лиды
todayActual/desired / Финансы tab / Пользователи tab / Проекты tab / Активность
tab с actor+summary / Войти как клиент / suspended disabled / 404 fallback /
500 fetch-error / overdue Просрочка / trial без оплаты).
- adminTenantDetailMapper.spec.ts +20 тестов: code/name/inn-empty/balanceRub
parse/mrrRub trial-null/status (4 ветки)/tariff (deriveTariff+fallback)/today
Actual+Desired/users (fullName / fallback)/projects/balanceHistory (TX- prefix +
chargeback type mapping)/activity (actor+summary)/metrics (4 поля)/activitySince.
- Vitest +23 (всего 416/416, +23 от 393).
Этап B эпика AdminTenantDetailView (frontend) ЗАКРЫТ. Эпик закрыт целиком (2 этапа).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 14:37:45 +03:00
Дмитрий
e0ffe7e686
phase2(reports-stage4): frontend integration ReportsView (replace mock)
...
- api/reports.ts: типизированные axios-helpers (listReportJobs/createReportJob/
retryReportJob/cancelReportJob/deleteReportJob) + ApiReportJob/Status/Format/
Counts/Quota interfaces. ensureCsrfCookie на mutating-вызовах.
- composables/reportsMapper.ts: mapApiReportJob (API → UI mock format с конверсией
pending→queued / processing→running). title строится на frontend'е (тип + period
с RU-месяцами «апр 2026» или диапазон «мар 2026 — апр 2026»). sizeText форматирует
bytes (B/KB/MB). timeText зависит от status (в очереди / в работе · Nс / N мин назад).
uiTypeToApi (deals → deals_export и т.д.).
- ReportsView.vue полностью переписан под API:
- onMounted → loadJobs (replace MOCK_JOBS на data из listReportJobs).
- usePolling 30 сек (фоновый авто-refresh).
- Submit → createReportJob → reload + success-alert + error-alert (validation+
общие ошибки извлекаются через extractValidationErrors/extractErrorMessage).
- canSubmit computed: disable если квота заполнена (active >= max).
- Reset-btn возвращает форму к defaults.
- Reload-btn (manual fast-path).
- Retry/Cancel/Download/Delete-кнопки → соответствующие API-вызовы;
Delete через v-dialog persistent confirm.
- fetch-error-alert на listReportJobs reject.
- Empty-state «Нет отчётов» когда jobs.length=0.
- canRetry проверяет retry_count<3 (max attempts CTO-6).
- Vitest +24 (всего 393/393, +24 от 369):
- reportsMapper.spec.ts +14: status mapping (pending/processing/done/failed) /
title (один месяц / диапазон) / format / sizeText (B/KB/MB/null) / attempt /
error / timeText (pending / processing / done «10 мин назад» / «только что») /
uiTypeToApi 4 slug'а / progress=50 для running.
- ReportsView.spec.ts переписан с MOCK_JOBS на vi.mock('api/reports') +12:
mount + listReportJobs called on mount / 4 type cards / default Сделки active /
4 формата / quota-banner из API / empty-state / done с Готов+Скачать /
failed с Ошибка+Повторить / failed retry_count=3 НЕ показывает Повторить /
pending с Отменить / Submit вызывает createReportJob+reload / Submit error →
submit-error-alert / Submit-btn disabled при квоте 3/3 / Reset / Reload-btn /
fetch-error-alert / Retry-btn / Cancel-btn / Delete confirm-dialog +
deleteReportJob.
Этап 4/4 эпика Reports backend ЗАКРЫТ. Эпик закрыт целиком.
Backend: 1 type (deals_export) × 4 формата (CSV/XLSX/JSON/PDF-stub).
Этап 2b (3 оставшихся типа: managers_summary/sources_summary/billing_summary)
— расширение через добавление 3 новых Provider-классов без изменений в архитектуре,
вынесено в Post-MVP backlog.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-09 13:49:55 +03:00