Последний автономный спринт. После этого watchdog молчит — все оставшиеся задачи требуют user-decisions / credentials / Windows-машины. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.4 KiB
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; HangfireOrgExportJobсобирает 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 dump —
deploy/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-docs —
DbSchemaDocsJobweekly воскр 05:00 UTC: читаетinformation_schema(НЕ EF-модель — источник правды = БД), генеритdb-schema-generated.mdс таблицами/колонками/FK + mermaid ER-диаграмма (топ-20 таблиц по числу FK). Скрывает AspNet*/OpenIddict*. - 5. Audit-log export API —
POST /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-status —
GET /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 в процессе:
OrgExportJob.WriteCollection<T>нуженwhere T : class(CS0452 на.AsNoTracking()).- Phase22a миграция забыла
UpdatedAt(унаследовано от Entity); первый POST упал 500 «column "UpdatedAt" does not exist». ДобавилADD COLUMN IF NOT EXISTSв миграции + сделал ALTER на stage вручную. - 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-docs →
DbSchemaDocsJob.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-провайдер.