Find a file
nns 6b0fc68f77
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
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 Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
feat(invoices+inventory): порт улучшений 05.10.2026 из sklad
Диапазон коммитов f455fa9..b7eb637 + 3ced706 (handoff).

Backend (src/food-market.api/Infrastructure/Invoices):
- Ean.cs — контрольная цифра EAN-8/13/UPC-A/GTIN-14 (ловит одну ошибку в цифре).
- TableReader.cs — своя читалка .xlsx/.csv без библиотек, UTF-8/1251,
  .xls → понятная ошибка; TableInvoiceParser — шаблон накладной.
- InvoiceModels: +Photo/BarcodeSource/Note в InvoiceLine, PhotoHint,
  IInvoiceExtractor.ExtractPhotosAsync.
- InvoiceMatcher.FindByBarcode — для photo-matching.
- InvoiceProcessor: ветки photos/excel/vision, MatchFromPhoto с EAN-проверкой
  (barcode_source="read" → валидация), SweepAbandonedPhotosAsync раз в час
  убирает папки needs_review старше 24ч; DeleteStored (owner-policy: НЕ копить).
- ClaudeCliInvoiceExtractor: ExtractPhotosAsync + BuildPhotosPrompt +
  FromPhotosJson (barcode_source → BarcodeSource, comment → Note, unmatched_photos
  → Warnings); дефолт модели claude-sonnet-5-5, PhotoTimeoutSeconds=600.

Backend (Controllers):
- POST /purchases/invoices/upload-photos (≤80 файлов, 60 МБ) +
  GET /purchases/invoices/{id}/photo/{n}; Apply/Delete убирают папку (не только файл).
- InvoiceDetailDto +Source/+HasFiles — клиент не ломится за 404 миниатюрами.
- POST /inventory/inventories/import — xlsx/csv → {found, unknown}, повторы ШК
  суммируются, документ не создаётся.
- Program.cs: UseResponseCompression + GzipCompressionProvider для application/json.
- InventoriesController.mobile-catalog: weak ETag + If-None-Match → 304;
  Cache-Control private max-age=60. Замер 31k: JSON 3.60 МБ → gzip 0.98 МБ.

Frontend:
- lib/shots.ts — ZXing TRY_HARDER на 1x+1600; compress JPEG 0.85 до 2400.
- components/PhotoSession.tsx — полноэкранная пачка (камера + готовые фото).
- components/CameraScanner.tsx: onCodeRef + эффект [], камера не закрывается
  после каждого скана.
- pages/InvoicesPage.tsx — четыре способа: камера одиночными, файл (xlsx/csv/img/pdf),
  камера многостраничная, фото-приёмка (камера или готовые фото) + «Отправить ещё раз».
- pages/InvoiceReviewPage.tsx — автосохранение 700 мс + индикатор; row-picker панель
  «в какую строку?» если fuzzy-match неуверен; linesRef; глобальный keydown; миниатюра
  снимка у строки; пометки Note.
- pages/SupplyScanPage.tsx + InventoryMobilePage.tsx — глобальный keydown.
- InventoryMobilePage: поле сканера на виду + импорт Excel/CSV.
- docs/supplier-invoice-template.xlsx — шаблон для поставщиков (9-я строка заголовки).

Хранение файлов (owner-policy 2026-10-05): фото НЕ копим.
- Обычная загрузка → удаление сразу после разбора.
- Фото-приёмка → удаление при Apply/Delete/24h abandoned.
- KeepFilesDays удалён из флоу (конфиг-ключ игнорируется).

Тесты (unit, зелёные):
- EanTests (6): валидные/невалидные/one-digit error.
- TableReaderTests (5): xlsx cells, шапка «Поставщик/Номер/Дата», CSV UTF-8+BOM,
  CSV Windows-1251, .xls friendly error.
- ClaudeCliInvoicePhotosParseTests (4): decoded проходит, source=null чистит Barcode,
  unmatched_photos → Warnings, comment → Note.
- InvoicePhotoRetentionTests (3): DeleteStored файл/папка/идемпотентность.

Preexisting ApiReferenceDocsJob (Sprint 28) failure не связан с портом.

Прогресс: docs/sklad-port-20261005-progress.md. Пользовательская инструкция:
docs/supply-inventory.md обновлена.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-06 00:02:13 +05:00
.claude feat(returns): возврат от покупателя (CustomerReturn) (P1-6) 2026-05-28 09:51:04 +05:00
.forgejo/workflows feat(public): :test ↔ test.admin, :latest ↔ admin; HTTPS-safe redirects 2026-10-04 17:14:55 +05:00
.github/workflows.disabled ci: disable .github/workflows — Forgejo Actions is the primary CI now 2026-04-23 17:10:22 +05:00
assets/brand chore(brand): add new food-market logo source SVG (FOOD/MARKET wordmark с яблоком) 2026-05-02 00:19:46 +05:00
badges test(s16): regression suite 35 flows + visual 60 snapshots + nightly + CI badges 2026-06-07 16:14:11 +05:00
deploy feat(stage): полная изоляция стенда от прод-ресурсов на prod-vm 2026-10-05 12:21:51 +05:00
docs feat(invoices+inventory): порт улучшений 05.10.2026 из sklad 2026-10-06 00:02:13 +05:00
scripts feat(invoices+inventory): порт улучшений 05.10.2026 из sklad 2026-10-06 00:02:13 +05:00
src feat(invoices+inventory): порт улучшений 05.10.2026 из sklad 2026-10-06 00:02:13 +05:00
tests feat(invoices+inventory): порт улучшений 05.10.2026 из sklad 2026-10-06 00:02:13 +05:00
.editorconfig Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
.gitattributes Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
.gitignore feat(public): Phase 6 — публичный маркетинговый сайт food-market.public на Astro 2026-04-26 19:11:34 +05:00
.nvmrc Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
CHANGELOG.md feat(s17): onboarding wizard + help kb + feedback + diagnostic + whats-new 2026-06-07 17:04:26 +05:00
CLAUDE.md Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
Directory.Build.props Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
Directory.Packages.props feat(s20): Mapster + SSO scaffold + maintenance automation (7 пунктов) 2026-06-07 21:54:12 +05:00
food-market.sln test(integration): Testcontainers.PostgreSql + WebApplicationFactory, 10 тестов (P1-21) 2026-05-27 03:14:01 +05:00
global.json Phase 0: project scaffolding and end-to-end auth 2026-04-21 13:59:13 +05:00
README.md docs: README counts up to date (240 endpoints, 58 controllers, 13 jobs) 2026-06-09 03:39:35 +05:00

food-market

🟢 **Quality:** [`docs/quality-status.md`](docs/quality-status.md)

CI Docker API Stage verify Regression coverage

Аналог системы МойСклад для розничной торговли в Казахстане. Multi-tenant SaaS + web-админка + Windows-касса. Поддерживает 8 типов документов учёта, ОФД-интеграцию (scaffolding), кассу на POS WPF с offline-буфером, отчёты, loyalty-programs, MoySklad-импорт, GDPR-export.

Состав

Часть Технологии Точка входа
API .NET 8 LTS, ASP.NET Core, EF Core 8, PostgreSQL 16, OpenIddict 5 src/food-market.api → http://localhost:5081
Web-админка React 19, Vite, TypeScript, Tailwind v4, TanStack Query, AG Grid src/food-market.web → http://localhost:5173
Public marketing Astro 5, TypeScript, Tailwind src/food-market.public → http://localhost:4321
POS-касса WPF .NET 8 Windows, SQLite, Refit+Polly, COM-весы src/food-market.pos (сборка кроссплатформенно, UI — Windows)

5-минутный quick start

git clone http://192.168.1.193:3000/nns/food-market.git
cd food-market

# БД (Postgres 14+ должен быть запущен, default user)
createdb -U $USER food_market

# Backend (миграции применятся на старте; Swagger на /swagger)
ASPNETCORE_ENVIRONMENT=Development dotnet run --project src/food-market.api &

# Web SPA
cd src/food-market.web && pnpm install && pnpm dev &

# Зарегистрироваться + получить токен
curl -X POST http://localhost:5081/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"organizationName":"Dev","email":"dev@local.test","password":"DevPass1!","phone":"+77001234567"}'

curl -X POST http://localhost:5081/connect/token \
  -d 'grant_type=password&username=dev@local.test&password=DevPass1!&client_id=food-market-web&scope=openid profile email roles api offline_access'

# Открыть http://localhost:5173 → залогиниться dev@local.test / DevPass1!

Подробнее — docs/ONBOARDING.md.

Где что лежит

food-market/
├── src/
│   ├── food-market.domain/          # POCO + enum'ы + interfaces. Без EF / ASP.NET.
│   ├── food-market.application/     # DTO, FluentValidation, MediatR-handler'ы, Mapster.
│   ├── food-market.infrastructure/  # EF Core, миграции, Identity, OpenIddict storage.
│   ├── food-market.api/             # Controllers (58, 240 endpoints), middleware, Hangfire jobs (13 recurring), OpenIddict server.
│   ├── food-market.web/             # React 19 SPA админки.
│   ├── food-market.public/          # Astro marketing-сайт.
│   ├── food-market.shared/          # DTO-контракты сервер↔POS.
│   ├── food-market.pos.core/        # POS-логика (UI-agnostic).
│   └── food-market.pos/             # WPF (.NET 8 Windows).
├── tests/
│   ├── food-market.UnitTests/       # xUnit + InMemory EF.
│   ├── food-market.IntegrationTests/# xUnit + Testcontainers Postgres.
│   ├── e2e/                         # Playwright + ad-hoc Python smoke.
│   └── load/                        # k6 (нагрузочные).
├── deploy/                          # Dockerfile.{api,web,public}, compose, nginx, prod-toolchain.
├── docs/                            # 50+ markdown файлов.
└── food-market.sln

Ключевая документация

  • ARCHITECTURE.md — общая картина: слои, deployment, что реализовано / scaffolding / не реализовано.
  • ONBOARDING.md — first 3 days для нового разработчика.
  • glossary.md — все доменные термины с ссылками на код.
  • MULTI-TENANCY.md — как изолируются org'и.
  • api-reference.md — auto-generated список всех 240 endpoint'ов (58 контроллеров).
  • error-codes.md — каталог HTTP-кодов для humanizeError на фронте.
  • secrets.md — env-vars + где хранятся секреты.
  • RUNBOOK.md — операционные процедуры (что делать при инциденте).
  • performance-baseline.md — k6 цифры + bottleneck'и.

Мультитенантность

Один процесс API обслуживает много организаций. Каждая видит только свои данные через EF Core query-filter по OrganizationId. SuperAdmin роль видит всё. См. MULTI-TENANCY.md.

Деплой

  • Stage: https://test.admin.food-market.kz. Деплой одной командой:
    ~/deploy-stage.sh  # docker build api+web → push в local registry → ssh prod-vm → compose up -d
    
  • Prod: https://admin.food-market.kz. Toolchain готов (Sprint 21):
    deploy/check-prod-readiness.sh        # backup+disk+health+env
    deploy/prod-deploy.sh <api-tag> <web-tag>  # blue-green
    deploy/prod-rollback.sh <to-tag>       # быстрый откат
    deploy/post-deploy-smoke.sh           # 10 шагов smoke + Telegram alert
    
    Реальный prod-сервер пока не настроен (DNS / certbot / nginx upstream).

Sprint-история (что было сделано)

Хронология в docs/sprintNN-progress.md. По состоянию на Sprint 28:

  • 1-7 — фундамент: auth (OpenIddict), multi-tenancy, каталог, документы, кассы.
  • 8-10 — отчёты, dashboard, dark mode + Cmd+K.
  • 11 — ОФД scaffolding (Webkassa / Kassa24 / ОФД-Соло).
  • 12-13 — документация / runbook / k6, security headers + rate-limits.
  • 14-15 — performance (bundle −51%, индексы, N+1 fix), a11y (WCAG-AA).
  • 16-17 — regression suite (44 Playwright specs), onboarding wizard + help.
  • 18 — TODO cleanup (P0 race, audit filters, notification center).
  • 19 — power UX (bulk-update, presets, Cmd+J, inline-edit, CSV import/export, keyboard nav).
  • 20 — Mapster + SSO scaffold + maintenance jobs (cleanup, VACUUM, disk-monitor, perf-regression).
  • 21 — stage→prod toolchain (7 deploy-скриптов + auto-tag).
  • 22 — data tooling: GDPR-export, 1C-CSV import, anonymize-prod, DB-schema docs, audit export streaming.
  • 23 — adversarial bug-hunt (4 bugs found + 4 fixed, includes CRITICAL 40001→500 fix).
  • 24 — docs cross-check + auto-generated API reference + ONBOARDING + integration-test gap-fill.
  • 25 — autonomous continuous quality monitoring: ~/quality-watchdog.sh hourly + Telegram + auto-incident loop + Hangfire quality-org-cleanup.
  • 26 — flaky-test detection + observability stack: find-flaky.sh, Grafana quality-watchdog.json, Prometheus alerts.yml + RUNBOOK action-per-alert.
  • 27 — cross-feature integration: tests/integration/ (6 specs) + 4h soak (k6) + crash recovery test.
  • 28 — overnight maintenance: api-reference auto-gen фикс (195→240), HSTS header on stage, integration spec gap-fill (1C-CSV, GDPR, security headers).

Лицензия

Internal proprietary, не для публикации без разрешения владельца.