food-market/docs/sprint5-progress.md
nns c43f68c39b docs(sprint5): TD-5 done — все 4 пункта выполнены, итог
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 16:47:32 +05:00

5.2 KiB
Raw Permalink Blame History

Спринт 5 — оптовые продажи, email, аудит, надёжность import-job

Автономная работа. После каждого пункта: dotnet build (SDK 8.0.126), unit + integration тесты, коммит порцией, отметка [x], коммит прогресса.

Multi-tenant: все новые сущности — TenantEntity с OrganizationId + query filter. E2E на изоляцию A vs B где применимо.

Чек-лист

  1. P1-5 Оптовая отгрузка (Demand) — Domain Demand+DemandLine (CounterpartyId юрлица, способ оплаты нал/безнал, цена опт., НДС). EF + миграция. Контроллер CRUD + Post/Unpost. Web /sales/demands. StockMovement тип WholesaleSale. Multi-tenant. Тесты. Зеркалит RetailSale без RetailPoint/Cashier; DemandPayment.Credit (постоплата/дебиторка), PaidAmount для отслеживания. Permissions переиспользуют существующие DemandsEdit/Post. Метрики documents_posted{type="demand"}. 3 интеграционных теста.
  2. P1-18 Аудит мутаций tenant'а — Domain OrgAuditLog (как SuperAdminAuditLog, но per-org). Hook через EF SaveChangesInterceptor на Supply/Sale/Demand/Product/Counterparty. UI: /audit-log для админа. Multi-tenant строго. Тесты. OrgAuditInterceptor снимает diff на SavingChanges (до commit) — атомарно с мутацией. ChangesJson: {"field":{"before":X,"after":Y}}. Белый список типов: Supply/SupplierReturn/RetailSale/Demand/Product/ ProductPrice/ProductBarcode/Counterparty. Web /audit-log с фильтрами и diff-viewer'ом. Tenant-isolation через query-filter. 3 интеграционных.
  3. P1-22 Email-шаблоны — расширить MailKit-сервис: Resources/EmailTemplates/*.html. Шаблоны: приглашение сотрудника с временным паролем (sendInvite=true), еженедельный summary владельцу (Hangfire recurring), low-stock alert (Hangfire daily). Тесты рендеринга. IEmailSender.SendHtmlAsync (multipart/alternative с plain fallback); EmailTemplateRenderer (mustache-light: {{key}} escape, {{{raw}}}, {{#key}}…{{/key}} условие); EmailTemplates загружает embedded Resources/EmailTemplates/*.html (Subject: первой строкой). Шаблоны: invite/weekly-summary/low-stock. Hangfire: weekly понедельник 07:00, low-stock ежедневно 08:00. 8 unit-тестов.
  4. TD-5 ImportJobRegistry в БД — сейчас in-memory ConcurrentDictionary, теряется при рестарте. Перевод на таблицу ImportJobs (Id, OrgId, Status, Progress, Total, StartedAt, FinishedAt, Errors JSON). Миграция. MoySkladImportController использует. Тесты. Domain.Integrations.ImportJob (TenantEntity); миграция Phase8c_ImportJobs. ImportJobRegistry теперь IServiceScopeFactory-backed: Create пишет строку немедленно, SaveAsync обновляет, Get/RecentlyFinished читают из БД. Контроллер MoySkladImportController.RunInBackgroundAsync дополнен periodic flush через Timer (каждые 2 сек) + финальный flush в finally — UI видит реальный прогресс, terminal-state сохраняется через рестарт. 3 интеграционных теста (survives across scope, RecentlyFinished, tenant-isolation).

Итог

Все 4 пункта выполнены. Спринт 5 завершён 2026-05-28.

Сводка:

  • P1-5 Demand — оптовая отгрузка контрагенту-юрлицу с DemandPayment.Credit и PaidAmount-полем; 3 интеграционных.
  • P1-18 OrgAuditLog — per-tenant журнал через SaveChangesInterceptor, atomic с мутацией, diff в jsonb; 3 интеграционных.
  • P1-22 EmailIEmailSender.SendHtmlAsync (multipart) + mustache-light renderer + 3 шаблона + 2 recurring Hangfire-джоба; 8 unit.
  • TD-5 ImportJob — persistence в БД, переживает рестарт, periodic flush для live-прогресса; 3 интеграционных.

Сборка: зелёная. Тесты: 35 unit + 68 integration = 103 зелёных.

Что осталось вне scope

  • ОФД-оператор (нужен внешний участник: Транском/Касса24);
  • MoySklad webhook-токены прод;
  • WPF/POS UI (Windows-SDK);
  • Стейдж→прод-деплой;
  • Real SMTP-сервер для прод (Mailgun/Sendgrid/etc).

Лог

  • Каждый пункт: build + тесты + коммит порцией + отметка [x] + коммит прогресса.
  • Все правки на main (origin Forgejo), без коммита global.json.