Commit graph

2 commits

Author SHA1 Message Date
nns 29a951a6ff feat(notifications): центр уведомлений + агрегация/эскалация минусов + каналы
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Персистентные уведомления (таблица notifications, Phase41) + REST
/api/notifications (список/счётчик/read/read-all) → центр уведомлений в вебе
(колокольчик, API-backed) и мобильном API.

Фоновый джоб NegativeStockNotificationJob (cron */5): агрегирует новые минусы
в ОДНО уведомление на склад (дебаунс по NotifiedAt + интервал орг., по умолч.
15 мин), уважает тихие часы (Asia/Almaty); эскалация просроченных (>N часов,
по умолч. 24) владельцу/админам. Получатели — админы, владелец, кладовщики
(право InventoryEdit). Каналы: SignalR (живой колокольчик), Telegram (владельцу),
push-заглушка.

Настройки организации: NegStockNotify{Enabled,IntervalMinutes,QuietFrom/ToHour,
EscalateHours} + GET/PUT /api/organization/settings + секция в настройках веба.
Блок «Просроченные минусы» на дашборде.

Тесты: unit тихих часов 3/3; integration — джоб создаёт уведомление админу,
дебаунс, read-all 3/3 (вся группа NegativeStockTests зелёная).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-09 02:56:59 +05:00
nns dd2e1e7af2 feat(realtime): SignalR hub /hubs/notifications per-org + dashboard live
Some checks are pending
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
P2-7 Sprint 8 пункт 1.

Backend:
- src/food-market.api/Realtime/NotificationsHub.cs — SignalR-хаб, группы
  org:{orgId:N}. JWT через Authorization-хедер (стандартно) или через
  query ?access_token=... (для WebSocket — браузерные не могут слать
  кастомные хедеры). SuperAdmin override через ?orgOverride=<id>.
- NotificationsPublisher.cs — singleton, IHubContext-обёртка.
- Program.cs — AddSignalR + MapHub. Middleware копирует ?access_token=
  в Authorization для /hubs/* до UseAuthentication.
- RetailSalesController.Post → публикует SalePosted + LowStockPayload
  если после движения товара остаток < MinStock. Best-effort: notify
  ошибка не валит транзакцию.
- SuppliesController.Post → SupplyPosted.

Events (camelCase в JSON):
- SalePosted { saleId, number, total, storeId, cashierName, retailPointId, postedAt }
- SupplyPosted { supplyId, number, total, supplierId, supplierName, postedAt }
- LowStock { productId, productName, storeId, storeName, quantity, minStock }

Web:
- @microsoft/signalr 10.0.0 client.
- src/lib/useNotificationsHub.ts — hook с автореконнектом, accessTokenFactory.
- DashboardPage:
  • liveRevenueDelta / liveCountDelta — оптимистическое приращение
    «Выручка сегодня» сразу при SalePosted (до refetch stats);
  • toast.info на SupplyPosted; toast.error на LowStock;
  • Wifi/WifiOff индикатор в header.

Тесты:
- SignalRNotificationsTests: A постит retail-sale → A получает SalePosted,
  B (другая org) НЕ получает — multi-tenant. ✓ 1/1 локально.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:29:59 +05:00