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 Public / Build + push Public (push) Waiting to run
Docker Public / Deploy Public 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
7 пунктов cleanup-спринта: 1. P0: race в GenerateNumberAsync — DocumentNumberRetry helper с WithOrgAdvisoryLockAsync (pg_advisory_xact_lock per orgHash/docTypeHash) + SaveWithRetryAsync exponential backoff. RetailSalesController POST обёрнут в lock. После — 23505 errors 53% → 0 на k6 baseline-replay. 2. HelpTooltip integration — ListPageShell расширен `helpTopic` пропом. Применено к 4 страницам (Promotions, Loyalty×2, AuditLog) + inline на MoySkladImportPage. 3. WhatsNewBanner — узкий emerald-toast сверху AppLayout. Опрашивает /api/whats-new (staleTime=1h), сравнивает buildVersion с localStorage.fm.lastSeenBuildVersion. Dismiss сохраняет версию. 4. Color contrast sweep — text-slate-400 в body-text узлах (empty-state, table-cells, hints, help) заменён на text-slate-500 dark:text-slate-400. 19 файлов. Иконки оставлены (decorative, не покрыты axe color-contrast). 5. useFormatCurrency() хук в lib/useFormatCurrency.ts. Берёт defaultCurrencySymbol из useOrgSettings + локаль из i18next. DashboardWidgets (TopProducts/RecentSales/Margin) переведены — `₸` больше не захардкоден. 6. Audit log UI filters — OrgAuditLogPage расширен полями «Кто» (Select сотрудников), «Дата с» / «по» (date-input'ы), кнопка «Сбросить фильтры». Backend уже умел эти параметры. 7. NotificationCenter — bell-icon в sidebar footer'е с unread badge, popover с 30 последних событий (Sale/Supply/LowStock через useNotificationsHub). Each item clickable → документ. In-memory. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
98 lines
6.2 KiB
Markdown
98 lines
6.2 KiB
Markdown
# Sprint 18 — TODO cleanup + P0 fix + UX polish
|
||
|
||
Цель: разгрести оставшиеся TODO из спринтов 14, 15, 17. Закрыть P0
|
||
из performance-baseline (race в GenerateNumberAsync), доделать
|
||
HelpTooltip integration, whats-new banner, color contrast, добавить
|
||
currency formatter, audit log filters, notification center.
|
||
|
||
Старт: 2026-06-07 (после Sprint 17). Исполнитель: Claude Opus 4.7.
|
||
|
||
## Принципы
|
||
|
||
- Каждый пункт — реальный фикс/измерение, не обещание.
|
||
- НЕ трогать: `global.json`, prod admin.food-market.kz, POS WPF.
|
||
|
||
## Чек-лист
|
||
|
||
- [x] **1. P0: race в GenerateNumberAsync** — `DocumentNumberRetry`
|
||
helper с двумя слоями: `WithOrgAdvisoryLockAsync` (PG advisory lock
|
||
per (orgHash, docTypeHash)) + `SaveWithRetryAsync` (exp backoff на
|
||
оставшихся 23505 от gap-cases). Применено к RetailSalesController
|
||
POST. После k6 baseline-replay: 23505 errors = **0** (было 53%).
|
||
- [x] **2. HelpTooltip integration** — `ListPageShell` расширен
|
||
optional `helpTopic` пропом → tooltip рендерится inline в заголовке.
|
||
Применено: PromotionsPage, LoyaltyProgramsPage, LoyaltyCardsPage,
|
||
OrgAuditLogPage. Для не-ListPageShell страниц (MoySkladImportPage)
|
||
— отдельный inline `<HelpTooltip>` под `PageHeader`.
|
||
- [x] **3. Whats-new banner toast** — `<WhatsNewBanner>` компонент
|
||
опрашивает `/api/whats-new` (staleTime=1h), сравнивает `buildVersion`
|
||
с `localStorage.fm.lastSeenBuildVersion`. На mismatch + items за
|
||
30 дней → узкий emerald banner сверху с count'ом feat/fix + ссылкой
|
||
на /whats-new. Кнопка X / клик по ссылке сохраняют новую версию.
|
||
Не показывается на buildVersion="dev". Вшит в AppLayout `<main>`.
|
||
- [x] **4. Color contrast sweep** — bulk fix: bare `text-slate-400`
|
||
на body-text-узлах (empty-states, table-cells, помощи, hints)
|
||
→ `text-slate-500 dark:text-slate-400`. Затронуло 19 файлов:
|
||
DashboardWidgets, DataTable, CommandPalette, EmptyStateWithDemo,
|
||
ProductPicker, SupplyLineQuickAdd, ProductGroupTree, Field,
|
||
ProductImageGallery, ShortcutsOverlay, SuperAdminLayout, + 8 pages.
|
||
Иконки (text-slate-400 на SVG) оставлены — на них axe color-contrast
|
||
не срабатывает (decorative).
|
||
- [x] **5. Currency formatter** — `useFormatCurrency()` хук в
|
||
`lib/useFormatCurrency.ts`. Берёт `defaultCurrencySymbol` из
|
||
useOrgSettings() + локаль из i18next. Возвращает stable `fmt(value, opts?)`.
|
||
DashboardWidgets (TopProducts/RecentSales/Margin) переведены на хук
|
||
— захардкоженный `₸` исчез из widget'ов. Бэкап fallback на тенге если
|
||
settings ещё не загрузились.
|
||
- [x] **6. Audit log UI filters** — OrgAuditLogPage расширен полями:
|
||
«Кто» (Select из /api/employees), «Дата с» / «по» (`<input type="date">`),
|
||
+ кнопка «Сбросить фильтры». Все 5 фильтров (entityType, action,
|
||
userId, from, to) триггерят refetch; параметры передаются в URL
|
||
query. Backend уже умел эти параметры (`OrgAuditLogController.List`).
|
||
- [x] **7. Notification center** — `<NotificationCenter>` компонент
|
||
в sidebar footer'е. Bell icon с unread badge (max 9+). Popover с
|
||
максимум 30 последних событий (SalePosted/SupplyPosted/LowStock через
|
||
существующий `useNotificationsHub`). Каждое событие clickable: ведёт
|
||
на документ. «Очистить» обнуляет ленту. Esc / click-outside закрывают.
|
||
Storage: in-memory (ephemeral) — для постоянной истории есть /audit-log.
|
||
|
||
## Журнал
|
||
|
||
### 2026-06-07 старт
|
||
Sprint 17 закрыт (7/7 ✓). Поехали по TODO cleanup.
|
||
|
||
### 2026-06-07 п.1 (P0 race fix)
|
||
Сначала ретрай-loop 5→10 на 23505 в `SaveOrFkErrorAsync` — сократил
|
||
ошибки 53%→24%→21%, но не убрал. Перешёл на PostgreSQL advisory
|
||
lock: `pg_advisory_xact_lock(orgHash, docTypeHash)` внутри transactions.
|
||
После — 0 ошибок 23505 на k6 baseline-replay (5 VUs, 100 RPS, single
|
||
org). Осталось 31% 40001 Serializable conflict'ов на stock_movements —
|
||
это другой issue (over-sell prevention), решается отдельно.
|
||
|
||
### 2026-06-07 п.2-3 (HelpTooltip + WhatsNewBanner)
|
||
HelpTooltip integration — расставлен в 4 страницах через ListPageShell
|
||
prop + 1 страницу через inline (MoySklad). WhatsNewBanner — узкий toast
|
||
сверху layout'a, dismiss persistent в localStorage.
|
||
|
||
### 2026-06-07 п.4 (color contrast)
|
||
Bulk-sed по 19 файлам — `text-slate-400` в текстовом content'е
|
||
заменён на `text-slate-500 dark:text-slate-400`. Иконки оставлены.
|
||
Получено 2 raunda doubled-class'ов от sed (text-slate-500
|
||
dark:text-slate-500 dark:text-slate-400) — почищено отдельным perl-passом.
|
||
|
||
### 2026-06-07 п.5-7 (currency + audit filters + notifications)
|
||
`useFormatCurrency()` + интеграция в DashboardWidgets. OrgAuditLogPage
|
||
получил Select сотрудников + 2 date-input'a + кнопку сброса.
|
||
NotificationCenter с bell-icon в sidebar — реюзает useNotificationsHub.
|
||
|
||
## Итог
|
||
|
||
Все 7 пунктов ✓. Локальные цифры:
|
||
- **P0 race**: 23505 errors 53% → **0** на k6 baseline-replay.
|
||
- **HelpTooltip**: 5 страниц получили deep-link на /help#topic.
|
||
- **WhatsNewBanner**: 1 emerald баннер в AppLayout, dismissible.
|
||
- **Contrast**: 19 файлов почищено, WCAG-AA для body text.
|
||
- **Currency**: 1 hook + 4 интеграции в DashboardWidgets.
|
||
- **Audit filters**: 5 серверных фильтров теперь имеют UI.
|
||
- **Notifications**: bell-popover с 30 событий, 3 типа, in-memory.
|