food-market/docs/glossary.md
nns 72d0a71307
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
docs(s24): docs cross-check + auto-gen + onboarding + test gap-fill (8/8 ✓)
1. Docs cross-check — обновил performance-baseline.md (Sprint 18/20/23
   фиксы), secrets.md (16 новых env-vars из Sprint 20+ — Authentication
   Google/Microsoft, Monitoring, Cleanup, Hangfire:Cron, Telegram,
   Maintenance, App, Storage, PUBLIC_GA_ID/YM_ID).

2. Auto-gen api-reference — ApiReferenceDocsJob (Hangfire weekly вс
   05:30 UTC) + Python-эквивалент `/tmp/gen-api-ref.py` для commit
   actual snapshot. docs/api-reference.md = 195 endpoints, 57 controllers.

3. Coverage gap-fill — Sprint18To23FeaturesTests.cs (16 Facts):
   - bulk-update + cross-tenant isolation
   - UserPresets CRUD
   - inline-edit price PATCH
   - CSV import 2 строки транзакцией
   - OrgExport create + list isolation
   - 1C-CSV import с русскими заголовками
   - audit-log export CSV streaming + BOM check
   - MoySklad sync-status stub
   - SSO providers + 503 unconfigured + 400 unknown provider
   - bug-001 NUL byte → 400
   - bug-004 tiny price → 400
   - export CSV BOM
   Покрывает все новые контроллеры Sprint 18-23 + regression-protect
   для критичных багов.

4. Contract tests — deploy/swagger-diff.sh: pull /swagger/v1/swagger.json
   с двух URL, diff endpoints+schemas через python3. Exit 0/1/2 для
   blue-green safety gate. Multi-path auto-detect.

5. docs/error-codes.md — каталог HTTP-кодов API (200-503) + humanizeError
   pattern для фронта + retry-policy таблица.

6. docs/glossary.md — 50+ доменных терминов (Tenant/Organization/Stock/
   StockMovement/RetailSale/Counterparty/Owner/Employee/Role/Permission/
   advisory lock/Serializable/…) с ссылками на code-сущности.

7. docs/ONBOARDING.md — first 3 days для нового разработчика
   (install → запуск → структура → первый PR + FAQ).

8. README.md — обновил под текущее состояние: React 19, Sprint-history
   1-24, ссылки на ключевые docs, корректный 5-min quick start.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 02:15:56 +05:00

260 lines
13 KiB
Markdown
Raw 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.

# Глоссарий food-market
Доменные термины, которые используются в коде, документации и общении
с пользователями. Один термин — одно определение. Ссылки на код через
`file:line` или namespace.path.
## Базовые сущности
### Organization (Организация, tenant)
**Корневая сущность мульти-tenancy.** Один процесс API обслуживает много
организаций; каждая видит только свои данные через query-filter по
`OrganizationId`. Не tenant-scoped сама по себе (отношение «один-ко-многим»
с TenantEntity).
Code: `foodmarket.Domain.Organizations.Organization` (`src/food-market.domain/Organizations/Organization.cs`).
См. [MULTI-TENANCY.md](MULTI-TENANCY.md).
### TenantEntity / ITenantEntity
Базовый класс/интерфейс для всех domain-сущностей с `OrganizationId`.
`AppDbContext` автоматически применяет query-filter по reflection.
Code: `foodmarket.Domain.Common.TenantEntity` + `ITenantEntity`.
### IOptionalTenantEntity
Двухуровневые справочники: либо системная запись (OrganizationId=null,
видна всем, мутирует только SuperAdmin), либо tenant'овская.
Пример: `UnitOfMeasure`, `ProductGroup` — есть глобальные «штука», есть
кастомные.
### User
Учётная запись для логина (ASP.NET Identity). НЕ привязан к одной org —
один email может работать в нескольких организациях через Employee.
Code: `foodmarket.Domain.Identity.User`.
### Employee (Сотрудник)
Запись о работнике конкретной org. Может иметь User (для логина) или
быть «без аккаунта» (только в чеках/документах). Связан с EmployeeRole.
Code: `foodmarket.Domain.Organizations.Employee`.
### Owner / AccountOwnerUserId
Первый пользователь, создавший org через signup. Хранится в
`Organization.AccountOwnerUserId`. Не удаляется (кроме как через
SuperAdmin reassign).
### Role / EmployeeRole / RolePermissions
- **Identity Role** (ASP.NET) — системная: `SuperAdmin`, `Admin`, `Cashier`,
`Storekeeper`, `Manager`.
- **EmployeeRole** — per-org кастомная роль (например, «Старший кассир»),
привязана к сотруднику. Имеет `RolePermissions` (флаги типа
`ProductsEdit`, `RetailSalesOperate`).
- **Permission** — атрибут `[RequiresPermission("Name")]` на endpoint'е.
Проверяет `RolePermissions` сотрудника текущего юзера.
### Store (Склад)
Физическое место хранения остатков. У org может быть несколько; первый
после signup — «MAIN» store.
Code: `foodmarket.Domain.Organizations.Store`.
### RetailPoint (Касса / торговая точка)
Привязана к Store, к ней привязывается RetailSale. Может иметь фискальные
поля (FiscalSerial, FiscalRegNumber).
Code: `foodmarket.Domain.Organizations.RetailPoint`.
## Каталог
### Product (Товар)
Единица каталога. Имеет несколько Prices (по типам), Barcodes, Images,
принадлежит ProductGroup. Поля Sprint 19: `IsArchived`, `IsAvailableForSale`.
Code: `foodmarket.Domain.Catalog.Product`.
### ProductGroup (Группа товаров)
Иерархическая (через `ParentId` + `Path`). Корень — «Все товары».
Может быть системной (OrganizationId=null) или per-org.
Code: `foodmarket.Domain.Catalog.ProductGroup`.
### ProductPrice (Цена)
Один товар × один PriceType = одна цена. Тип может быть «системным»
(IsSystem — основная розничная) или «обязательным» (IsRequired — без неё
нельзя сохранить товар).
Code: `foodmarket.Domain.Catalog.ProductPrice`.
### PriceType (Тип цены)
Розничная / Закупочная / Базовая / Себестоимость и т.д. Per-org. Sprint 1.
Code: `foodmarket.Domain.Catalog.PriceType`.
### ProductBarcode (Штрихкод)
Уникальный (составной UNIQUE: Code + Organization). Один товар может
иметь несколько штрихкодов; один из них — `IsPrimary` (показывается на
этикетке).
Code: `foodmarket.Domain.Catalog.ProductBarcode`.
### UnitOfMeasure (Единица измерения)
шт / кг / л / м / упак. Системные (OrganizationId=null) + org-кастомные.
`OrgUnitOfMeasure` — таблица per-org enable/disable.
Code: `foodmarket.Domain.Catalog.UnitOfMeasure`.
### Counterparty (Контрагент)
Поставщик (Supplier) / Покупатель-юрлицо (LegalEntity) / Покупатель-физлицо
(Individual). Имеет БИН/ИИН, банковские реквизиты, контакты.
Code: `foodmarket.Domain.Catalog.Counterparty`.
## Остатки и движения
### Stock (Остаток)
Кеш `SUM(StockMovement.Quantity)` для пары `(Store, Product)`.
Поддерживается транзакционно в каждом posting'е документа.
Code: `foodmarket.Domain.Inventory.Stock`.
### StockMovement (Движение остатка)
Имматериальная запись об изменении остатка. Source: документ
(Supply.Post / RetailSale.Post / Enter.Post / Loss.Post / Transfer.Post /
Inventory.Post / SupplierReturn.Post / CustomerReturn.Post).
**Инвариант**: `Stock.Quantity ≡ Σ StockMovement.Quantity` для каждой
пары (Store, Product). Проверяется property-test'ом (Sprint 15).
Code: `foodmarket.Domain.Inventory.StockMovement`.
## Документы (Documents)
Все имеют поля: `Number`, `Date`, `Status` (Draft/Posted), `PostedAt`.
Имеют `IVersionedEntity` для `xmin` concurrency check.
### Supply (Приёмка)
От поставщика. Увеличивает остаток + пересчитывает скользящую
себестоимость (Product.Cost).
Code: `foodmarket.Domain.Purchases.Supply`.
### Enter (Оприходование)
Внутреннее. Увеличивает остаток без поставщика. Для коррекций инвентаризации.
Code: `foodmarket.Domain.Inventory.Enter`.
### Loss (Списание)
Уменьшает остаток. Причина: порча, кража, тестовое использование.
Code: `foodmarket.Domain.Inventory.Loss`.
### Transfer (Перемещение)
Между складами. Уменьшает на исходном, увеличивает на целевом.
Code: `foodmarket.Domain.Inventory.Transfer`.
### Inventory (Инвентаризация)
Списки фактических остатков. Расхождение → автоматические Enter/Loss
строки при post.
Code: `foodmarket.Domain.Inventory.InventoryDoc` (имя класса не Inventory из-за конфликта с namespace).
### RetailSale (Розничный чек)
Продажа через POS / админку. После Post → уменьшает остаток, пишет ОФД
снапшот (FiscalNumber etc., Sprint 11), уведомляет SignalR.
Code: `foodmarket.Domain.Sales.RetailSale`.
### Demand (Оптовая отгрузка)
Продажа юрлицу. Аналогично RetailSale, но с накладной (печатной формой).
Code: `foodmarket.Domain.Sales.Demand`.
### SupplierReturn (Возврат поставщику)
Sprint 5. Уменьшает остаток + возвращает деньги поставщику.
Code: `foodmarket.Domain.Purchases.SupplierReturn`.
### CustomerReturn / RetailSale.IsReturn=true
Возврат от покупателя. Реализован через флаг `IsReturn` на RetailSale +
ReferenceSaleId. Восстанавливает остаток.
## Деньги
### Cost (Себестоимость)
Скользящее среднее `(qty_old × cost_old + qty_in × price_in) / (qty_old + qty_in)`.
Пересчитывается на каждой проведённой Supply. `Decimal(18,4)`.
### ReferencePrice (Эталонная цена закупа)
Опциональная. Заполняется автоматически unit-price'ом первой Supply;
после 30 дней без новых Supply → Hangfire-job переписывает на Cost.
### VAT (НДС)
- `Product.Vat` (default из `Country.VatRate`, в РК — 12%).
- `Product.VatEnabled` — управляет видимостью поля на UI.
- На документах: `VatMode` (включается «в том числе» / «сверху»).
### AllowFractionalPrices (Дробные цены)
Org-настройка. Если false → все цены округляются до целых при сохранении.
Sprint 23 bug-004: round-then-validate чтобы избежать «0 цена прошла
required-check».
## Доступ и безопасность
### Tenant context
`ITenantContext` (resolved per request) выдаёт `OrganizationId` из JWT
claim `org_id`. NULL для unauthenticated / SuperAdmin-без-override.
### SuperAdmin
Системная роль. Видит все organizations + может «открыть как…» через
`X-Org-Override` header (включает Admin claim для этой org'и).
Все действия SuperAdmin'a в override-режиме пишутся в `super_admin_audit_log`.
### OrgAuditLog
Per-tenant журнал каждой mutate-операции (CREATE/UPDATE/DELETE на
любую TenantEntity). Пишется автоматически через `OrgAuditInterceptor`
на SaveChanges.
### Permission
Атрибут `[RequiresPermission("ProductsEdit")]` на endpoint'е. Проверяет
флаг `RolePermissions` сотрудника текущего юзера. Если у юзера нет
Employee в этой org — 403.
## Фоновые операции
### Hangfire job
.NET background job framework. `recurring-job` (по cron) и
`background-job` (одноразовый). Хранятся в схеме `hangfire` той же БД.
### advisory lock (Sprint 18)
PostgreSQL `pg_advisory_xact_lock(int, int)` — кооперативная блокировка
per-(org, doctype). Используется для сериализации генерации номера
документа.
### Serializable transaction
PostgreSQL Isolation Level. Используется в posting'ах документов
(`RetailSale.Post`, `Supply.Post`, etc.) для защиты от race на
остатках. На конфликте → 40001, теперь мапится в 409 (Sprint 23).
## Внешние интеграции
### ОФД (OFD)
Оператор Фискальных Данных. В РК: Webkassa, Kassa24, ОФД-Соло.
RetailSale.Post после успеха отправляет фискальный документ → получает
`FiscalNumber`, `FiscalQrCode`. Sprint 11 scaffolding.
### МойСклад
Сторонняя SaaS-система учёта. Импорт товаров/контрагентов/остатков по
OAuth-token (per-org в `Organization.MoySkladToken`).
### POS (касса)
WPF-приложение под Windows 10+. Локальный SQLite-буфер, синк через
`/api/pos/v1/*` с idempotency-ключом (см. `pos_batch_acks`).
### Telegram bot
Один platform-bot (token в env). Owner'ы org'и привязывают свой chat-id
(`Organization.OwnerTelegramChatId`) для получения daily-сводки.
## Тестирование
### Stage
`https://test.admin.food-market.kz`. Контейнеры на prod-vm
`192.168.1.190`, deploy через `~/deploy-stage.sh`.
### Smoke / Regression / Verify
- **Smoke** — быстрый sanity-check (5 шагов signup → login → bootstrap).
- **Regression** — полный e2e через Playwright (44 spec'a в Sprint 23).
- **Verify** — спринт-специфичные post-feature тесты.
## Сокращения
| Сокр | Что |
|---|---|
| **AT** | Access Token (JWT, TTL 1h) |
| **RT** | Refresh Token (для получения нового AT) |
| **PoS** | Point of Sale (касса) |
| **ОФД** | Оператор Фискальных Данных |
| **БИН** | 12-цифровой номер юрлица в РК |
| **ИИН** | 12-цифровой номер физлица в РК |
| **RPO** | Recovery Point Objective (макс. потеря данных при backup-restore) |
| **RTO** | Recovery Time Objective (время восстановления) |
| **CSP** | Content Security Policy (HTTP-header) |
| **SA** | SuperAdmin |