AppLayout брал заголовок топбара только из sidebar navItems → /reminders и
/import (которых нет в боковом меню) показывали fallback «Страница». Добавлен
fallback на route.meta.title перед «Страница». TDD: AppLayout.spec.ts (RED→GREEN).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deals page redesign: design spec + implementation plan (Phase A page redesign,
Phase B 14->5 status funnel) + v8 HTML mockups (variants comparison + final).
AppSidebar: remove Импорт данных / Отчёты nav links (routes stay reachable by
direct URL); AppLayout.spec updated to 6 nav items. stylelint --fix on mockups;
cspell-words += deals-redesign terms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Закрывает этап 2 P0 целиком (UI bell с unread badge + polling).
Backend:
- App\Http\Controllers\Api\InAppNotificationController под auth:sanctum:
GET /api/notifications?unread_only=&limit= (1..100 default 50);
PATCH /api/notifications/{id}/read (idempotent);
POST /api/notifications/mark-all-read (bulk + count);
DELETE /api/notifications/{id}.
- Route::middleware('auth:sanctum')->prefix('/api/notifications') в web.php.
- DB::transaction + SET LOCAL app.current_tenant_id для RLS.
- Защита от кражи чужого id через where('user_id', $auth->id).
- Pest +14 (305/305 за 34.71 сек, 1099 assertions).
Frontend:
- api/notifications.ts — типизированные axios-helpers + ensureCsrfCookie.
- stores/notifications.ts — Pinia: items/unreadCount/total/loading +
optimistic markRead/markAllRead/remove с revert на reject.
- AppLayout: bell-icon → v-menu offset=8 location=bottom-end:
pip badge показывает unreadDisplay (1..99 / 99+ / hidden);
v-list последних 10 из sortedItems с event-icon + formatRelative;
Mark-all-read btn только при unreadCount > 0;
click на item → markRead + router.push('/deals') если deal_id.
- usePolling(loadNotifications, {intervalMs: 30_000}) с Page Visibility.
- loadNotifications no-op без auth.user.
- Vitest +18 (339/339 за 20.03 сек): store 12 + AppLayout +6
(bell-btn / pip скрыт при 0 / pip count / 99+ / listNotifications
на mount с user / no-op без user).
PHPStan baseline регенерирован (50 Pest false-positives подавлены).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>