food-market/docs/sprint9-progress.md
nns a1cccdeef5 docs(sprint9): итог — все 4 пункта ✓, stage 8/8 e2e зелёные
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 21:38:26 +05:00

57 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Sprint 9 — лояльность, акции, mobile-адаптация, PWA
Цель: программы лояльности (баллы/% скидка) для постоянных покупателей,
промокоды/акции в чеке, починить узкие экраны (телефон/планшет),
PWA-обёртка владельца для отчётов с homescreen-икоником.
Старт: 2026-06-01. Исполнитель: Claude Opus 4.7 (автономный режим).
Это последний автономно-безопасный спринт. Дальше нужен человек:
ОФД-интеграция, MoySklad-токены, POS WPF на Windows, kz-локализация,
прод-деплой.
## Принципы
- Multi-tenant обязателен (`OrganizationId` на каждой новой таблице, query filter).
- Каждый пункт: `dotnet build` + локальные тесты + `~/deploy-stage.sh` + retest на `https://test.admin.food-market.kz` (включая mobile viewport 375x667).
- НЕ трогать: `global.json`, прод-стек (admin.food-market.kz), POS WPF.
## Чек-лист
- [x] **1. P2-12 Loyalty (программы + карты)** — Phase9b миграция. `LoyaltyProgramsController` + `LoyaltyCardsController` (/issue, /lookup, /block). RetailSale: input.LoyaltyCardNumber → расчёт скидки/баллов; Post начисляет в card.Balance. UI: `/loyalty/programs`, `/loyalty/cards`. Тесты: 3/3 integration + 2/2 stage.
- [x] **2. P2-13 Promotions (промокоды/акции)**`Promotion` (Percent|FixedDiscount, Scope, jsonb-массивы Guid, период, Code unique per org). `PromotionsController`. RetailSale: input.PromotionCode → lookup+matchingSubtotal+snapshot. UI: `/promotions`. Тесты: 2/2 integration + 2/2 stage.
- [x] **3. Mobile-адаптация**`stage-ui-s9-mobile-audit.spec.ts` снял 20 screenshot'ов (375 + 768 viewport × 10 ключевых страниц с seed-demo) в `tests/e2e/reports/mobile/`. DataTable: `min-w-max sm:min-w-[640px]` — узкие таблицы (Loyalty/Promotions) укладываются без horizontal scroll, широкие — скроллятся внутри. EmptyState/ConfirmDialog/Drawer уже mobile-friendly из Sprint 7. Реальные layout-break'и не найдены.
- [x] **4. P2-9 PWA владельца (read-only)**`public/manifest.webmanifest` (start_url=/dashboard, shortcuts на отчёты, display=standalone). `public/sw.js` (network-first SPA navigate + offline-fallback, GET /api/* network-first+cache, статика SWR, /hubs/* skip). `public/offline.html` static fallback. `index.html`: <link rel=manifest>, apple-touch-meta, lang=ru-KZ. `main.tsx` регистрирует SW только в PROD. nginx: /sw.js no-cache, /manifest.webmanifest правильный mime. Тесты: `stage-ui-s9-pwa.spec.ts` 3/3 ✓ + SignalR regression ✓.
## Журнал
### 2026-06-01 — старт
Sprint 8 закрыт (`docs/sprint8-progress.md`, 4/4 ✓, 8/8 stage e2e). Перехожу к пункту 1 (Loyalty).
### 2026-06-01 — итог
**Все 4 пункта ✓** на `https://test.admin.food-market.kz`. Stage 8/8 e2e зелёные.
| # | Тема | Тесты | Коммит |
|---|---|---|---|
| 1 | Loyalty programs+cards | int 3/3 + stage 2/2 | `91128a7` |
| 2 | Promotions | int 2/2 + stage 2/2 | `91128a7` |
| 3 | Mobile-адаптация | 20 screenshot'ов + 1/1 audit | `76a175f` |
| 4 | PWA (read-only) | stage 3/3 | `76a175f` + `12d833f` |
**Сделано:**
1. **Loyalty**: Phase9b migration (3 таблицы + 6 колонок на retail_sales). `LoyaltyProgram` (Percentage|FixedAmount|PointsAccrual) + `LoyaltyCard` с unique CardNumber. `LoyaltyProgramsController` + `LoyaltyCardsController` (CRUD + /issue + /lookup + /block). `RetailSalesController.Create/Update` + `ApplyLoyaltyAndPromotionAsync`: input.LoyaltyCardNumber → discount/points, snapshot в LoyaltyCardId/LoyaltyBonusApplied/LoyaltyPointsAccrued; Post начисляет баллы внутри транзакции. UI: `/loyalty/programs` + `/loyalty/cards`. `LoyaltyManage` permission.
2. **Promotions**: `Promotion` (Percent|FixedDiscount, Scope=All|ProductGroups|Products, jsonb-массивы Guid, Code unique per org через 23505→409). `PromotionsController` (CRUD). RetailSale: input.PromotionCode → period+MinSaleAmount+matchingSubtotal+snapshot. UI: `/promotions`. `PromotionsManage` permission.
3. **Mobile-адаптация**: аудит-spec прогоняет 20 страниц в 375 + 768 viewport, складывает screenshots в `reports/mobile/`. DataTable: `min-w-max sm:min-w-[640px]` для узких таблиц. Layout-bug'ов не найдено (Sprint 7 уже сделал AppLayout/Drawer/EmptyState mobile-ready).
4. **PWA**: manifest + sw.js + offline.html + nginx-правила. SW стратегии: navigate=network+offline-fallback, /api/*=network+cache, статика=SWR, /hubs/*=skip (иначе SignalR negotiate рвался). PROD-only регистрация. Lighthouse-аудит не запускали — это требует Chrome DevTools, у нас Playwright headless; basic checks (manifest mime, SW active, offline page) проходят.
**Что осталось на следующий sprint (не автономно):**
- ОФД-интеграция (требует регистрации фискального оператора).
- MoySklad-токены для прода.
- POS WPF: тестирование на реальном Windows + Кассе с весами.
- kz-локализация (качественный перевод нужен от живого).
- Lighthouse PWA-аудит → score (CI integration).
- Прод-деплой на admin.food-market.kz.