food-market/docs/sprint22-progress.md
nns b6f3c55d81
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
docs(s22): итог — 7/7 ✓ + 10/10 endpoint smoke + ARCHITECTURE финал
Последний автономный спринт. После этого watchdog молчит — все
оставшиеся задачи требуют user-decisions / credentials / Windows-машины.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 23:14:42 +05:00

8.4 KiB
Raw Blame History

Sprint 22 — data tooling: export/import, schema docs, anonymized dump

Цель: финальный спринт автономной работы. GDPR-ready export, 1С-import, схема-документация, audit-export, anonymized stage dump, MoySklad status endpoint, итоговый ARCHITECTURE.

Старт: 2026-06-07 (после Sprint 21). Исполнитель: Claude Opus 4.7. Последний автономный спринт — после очередь пустая, watchdog молчит.

Принципы

  • Все export/import — multi-tenant строго (нельзя выгрузить чужое).
  • Долгие операции — Hangfire job + status polling (не блокировать HTTP).
  • НЕ трогать: global.json, prod admin.food-market.kz, POS WPF.

Чек-лист

  • 1. GDPR-export организации — domain OrgExport (Phase22a: jsonb-like fields, unique download token). POST /api/org/export → 202 + id; Hangfire OrgExportJob собирает ZIP с JSON каждой сущности (organizations, stores, retail-points, employees, product-groups, products, prices, barcodes, counterparties, stocks, stock-movements, supplies, supply-lines, retail-sales, org-audit-log + README.md + metadata.json) через IObjectStorage, генерирует 64-hex token, expires 24h, email-notify. GET /api/org/export[/{id}] + GET /api/org/export/download/{token} (anonymous, token-protected).
  • 2. CSV-импорт из 1СPOST /api/catalog/products/import/1c-csv: Content-Type charset auto-detect (UTF-8 BOM / Windows-1251 / другие), разделитель ; или , (по большинству в header'е), русские заголовки (Артикул/Наименование/Единица/Цена/Группа/Штрихкод) или английские. Unit-коды нормализуются (шт/кг/г/л/мл/упак/etc). Делегирует на универсальный ImportCsv (одна транзакция, multi-tenant query-filter). docs/imports.md с примером + curl.
  • 3. Anonymized prod dumpdeploy/anonymize-prod.sh:
    • pg_dump прода через ssh+docker exec в кастом-формат
    • pg_restore во временную локальную БД food_market_anon_$$
    • UPDATE AspNetUsers (email→user{N}@example.kz, phone→+7700111{N:04}, PasswordHash→тестовый, SecurityStamp/ConcurrencyStamp→random)
    • UPDATE employees (имена→Тестов{N}, контакты)
    • UPDATE counterparties (BIN/IIN→синтетические 12-цифр, контакты)
    • UPDATE organizations (MoySkladToken=NULL, OwnerTelegramChatId=NULL)
    • REVOKE OpenIddictTokens
    • TRUNCATE audit-логи
    • pg_dump → gz файл
    • DROP temp-БД через trap
  • 4. DB schema auto-docsDbSchemaDocsJob weekly воскр 05:00 UTC: читает information_schema (НЕ EF-модель — источник правды = БД), генерит db-schema-generated.md с таблицами/колонками/FK + mermaid ER-диаграмма (топ-20 таблиц по числу FK). Скрывает AspNet*/OpenIddict*.
  • 5. Audit-log export APIPOST /api/admin/audit-log/export?format=csv|jsonl: стримит через AsAsyncEnumerable().WithCancellation(ct) без полной материализации. UTF-8 BOM для CSV (Excel-RU). Фильтры: from/to/entityType/userId. Multi-tenant через query-filter.
  • 6. MoySklad sync-statusGET /api/moysklad/sync-status: { configured: bool, lastSuccessAt, errorCountLast7Days, pendingCount, byKind: { products: KindStatus, counterparties: KindStatus } }. Stub-режим (configured=false) если Organization.MoySkladToken пуст.
  • 7. Final ARCHITECTURE.md — обновил с разделами:
    • Sprint 13-22 changes (быстрая сводка) — добавил строки 16-22
    • Реализовано полностью — 9 пунктов про backend / catalog / reports / background / observability / a11y / tests / web / POS / DevOps
    • Scaffolding (готово к подключению, но не активно) — таблица с 9 пунктами: SSO Google/Microsoft, 3 ОФД-провайдера, MoySklad, Telegram-alerts, Yandex.Metrika/GA4, SMTP, MinIO. Каждый row указывает «что нужно от user'а».
    • Не реализовано — 6 пунктов (прод-деплой, SSO callback flow, KZ-перевод, POS Windows-тест, down-migrations, public-site SEO).
    • Актуальная файловая структура.

Журнал

2026-06-07 старт

Sprint 21 закрыт (7/7 ✓). Поехали по data tooling — финальный sprint.

2026-06-07 итог

Все 7 пунктов ✓. Stage deploy + retest:

Hotfixes в процессе:

  1. OrgExportJob.WriteCollection<T> нужен where T : class (CS0452 на .AsNoTracking()).
  2. Phase22a миграция забыла UpdatedAt (унаследовано от Entity); первый POST упал 500 «column "UpdatedAt" does not exist». Добавил ADD COLUMN IF NOT EXISTS в миграции + сделал ALTER на stage вручную.
  3. 1C-CSV import возвращал «не найдена колонка Наименование» — DetectEncoding падал на Windows-1251 для UTF-8 без BOM. Теперь сначала смотрит Content-Type charset=…, потом BOM, потом win-1251.

Sprint 22 endpoint smoke (10 проверок, все ✓):

Endpoint Статус Результат
POST /api/org/export 202 Pending (id выдан)
GET /api/org/export/{id} (polling) 200 Status=Ready после 1.7с
GET /api/org/export/download/{token} 200 5254 bytes ZIP, application/zip
GET /api/org/export (list) 200 count=1
POST /api/catalog/products/import/1c-csv 200 created=2 (русский заголовок ✓)
POST /api/admin/audit-log/export?format=csv 200 2943 bytes streaming
POST /api/admin/audit-log/export?format=jsonl 200 4280 bytes streaming
GET /api/moysklad/sync-status 200 configured=false (stub-режим)
stage-smoke scenarios 5/5 ✓
stage-audit-log scenarios 7/7 ✓

Hangfire-job registered: recurring-job:db-schema-docsDbSchemaDocsJob.GenerateAsync cron 0 5 * * 0 (вс 05:00 UTC).

Итог

Все 7 пунктов ✓. Локальные цифры:

  • GDPR-export: 5KB ZIP за 1.7с для пустой org'и; для реальной org'и с 1000 товаров + 10k движений — оценка <30с.
  • 1C-CSV import: 2 строки за <100ms, отдельный endpoint без дублирования транзакционной логики.
  • Anonymize: bash-скрипт, тестировал bash -n; реальный прогон невозможен на dev-vm без доступа на прод.
  • DB schema docs: cron зарегистрирован, первый прогон в вс 05:00 UTC. Файл /app/db-schema-generated.md пока не создан (cron ещё не сработал).
  • Audit export: streaming через AsAsyncEnumerable; на 5KB ничего тяжёлого не видно, но архитектурно готов к миллионам строк.
  • MoySklad status: 8ms ответ, stub-режим корректно отдаёт configured=false.
  • ARCHITECTURE.md: 470 строк, секции «Реализовано» / «Scaffolding» / «Не реализовано» — это финальный документ для передачи системы.

Заключение (после 22 спринтов)

Все автономные задачи закрыты. Дальнейшее автономное добавление — work-for-the-sake-of-work без явного запроса юзера. Touch'аем ~/.fm-watchdog/DONE и ждём пока user не вернётся с конкретным запросом, требующим внешних решений: prod-deploy, OAuth-keys, ОФД-keys, Windows-тестирование POS, kz-перевод, реальный SMTP-провайдер.