food-market/docs/sprint18-progress.md
nns 9bd4375ae4
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
feat(s18): TODO cleanup — P0 race fix + helpTooltip + whats-new + contrast + currency + audit filters + notifications
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>
2026-06-07 18:50:35 +05:00

6.2 KiB
Raw Blame History

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.

Чек-лист

  • 1. P0: race в GenerateNumberAsyncDocumentNumberRetry helper с двумя слоями: WithOrgAdvisoryLockAsync (PG advisory lock per (orgHash, docTypeHash)) + SaveWithRetryAsync (exp backoff на оставшихся 23505 от gap-cases). Применено к RetailSalesController POST. После k6 baseline-replay: 23505 errors = 0 (было 53%).
  • 2. HelpTooltip integrationListPageShell расширен optional helpTopic пропом → tooltip рендерится inline в заголовке. Применено: PromotionsPage, LoyaltyProgramsPage, LoyaltyCardsPage, OrgAuditLogPage. Для не-ListPageShell страниц (MoySkladImportPage) — отдельный inline <HelpTooltip> под PageHeader.
  • 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>.
  • 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).
  • 5. Currency formatteruseFormatCurrency() хук в lib/useFormatCurrency.ts. Берёт defaultCurrencySymbol из useOrgSettings() + локаль из i18next. Возвращает stable fmt(value, opts?). DashboardWidgets (TopProducts/RecentSales/Margin) переведены на хук — захардкоженный исчез из widget'ов. Бэкап fallback на тенге если settings ещё не загрузились.
  • 6. Audit log UI filters — OrgAuditLogPage расширен полями: «Кто» (Select из /api/employees), «Дата с» / «по» (<input type="date">),
    • кнопка «Сбросить фильтры». Все 5 фильтров (entityType, action, userId, from, to) триггерят refetch; параметры передаются в URL query. Backend уже умел эти параметры (OrgAuditLogController.List).
  • 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.