# CHANGELOG

Auto-generated from git log feat:/fix: (last 90 days).

## 2026-06-07

- **feat**: security headers + rate-limits + sensitive-ops audit + session revoke + Grafana (s13)
- **feat**: ОФД-scaffolding — IFiscalProvider + 4 провайдера + UI/тесты (s11)

## 2026-06-06

- **feat**: dark mode полировка + Cmd+K палитра + аудит-spec (s10-4)
- **feat**: глобальная Cmd+K палитра + GET /api/search/global (s10-3)
- **feat**: year-demo seeder + 4 dashboard виджета + week-stats (s10)

## 2026-06-04

- **fix**: IP-limit 60/min, locale ru-RU в playwright, исправлены payload'ы verify-spec'ов (stage-tests)
- **fix**: per-username 5/мин + per-IP 30/мин — brute-force на конкретный аккаунт ловится, CI/NAT не страдают (rate-limit)
- **fix**: rate-limit 5/min на /connect/token, nginx route /metrics+/swagger, Swagger в Production через IncludeSwagger (stage)

## 2026-05-31

- **fix**: bump cache version + filter SignalR-race errors in PWA test (pwa)
- **fix**: SW не вмешивается в /hubs/* — SignalR negotiate сломался (pwa)
- **feat**: PWA owner read-only + mobile tweaks + S9 stage specs (pwa+mobile+s9)
- **fix**: убрать unused imports (TS6133) (loyalty)
- **feat**: P2-12 + P2-13 — лояльность и промокоды (Sprint 9 п.1-2) (loyalty+promotions)
- **feat**: IObjectStorage abstraction (Local + MinIO) — P2-15 (storage)
- **feat**: react-i18next ru/en + language switcher (P2-6a — базовая) (i18n)
- **feat**: OwnerDailySummaryJob + bot binding (P2-14) (telegram)
- **feat**: SignalR hub /hubs/notifications per-org + dashboard live (realtime)

## 2026-05-30

- **fix**: после create — invalidate list query (не показывался сразу) (employees)
- **fix**: error display через humanizeError, не «Request failed» (employees)
- **fix**: уберём cache-touch после Delete — просто navigate (catalog)
- **fix**: после Delete не refetch'аем удалённый товар (catalog)
- **fix**: ProductEditPage — race на currencies.data + читаемая ошибка (catalog)
- **fix**: Modal — role=dialog + aria-modal + aria-label на крестике (a11y)
- **fix**: useShortcuts — бэр-клавиши не зависят от Shift (web)
- **feat**: keyboard shortcuts на edit + list страницах + «?» overlay (web)
- **feat**: Breadcrumbs на edit-страницах (Каталог / Товары / Молоко 3.2%) (web)
- **feat**: Empty states с CTA на list-страницах (web)
- **feat**: loading skeletons вместо «Загрузка…» в DataTable + edit-pages (web)
- **feat**: toast-система — error на 4xx/5xx + success на мутации (через meta) (web)
- **feat**: ConfirmDialog компонент + useConfirm hook вместо window.confirm() (web)
- **feat**: demo-data seeder для test.admin.food-market.kz (stage)

## 2026-05-29

- **fix**: operationId + schemaId — генерация OpenAPI работает (swagger)
- **fix**: 3 фикса по итогам stage-тестирования (reports)
- **fix**: EF8 nav-collection bug в Enters/Losses/Transfers/SupplierReturns/Inventories.Update (docs)
- **fix**: EF8 nav-collection bug в Products.Update + unique IX на Article (catalog)

## 2026-05-28

- **feat**: TOTP 2FA для админов через AuthenticatorTokenProvider (P2-4) (auth)
- **feat**: MediatR partial — 3 handler-образца (TD-1) (cqrs)
- **feat**: структурные log-fields в Serilog (TD-4) (logging)
- **feat**: FluentValidation + ValidationFilter для DTO (TD-2) (validation)
- **feat**: RowVersion на документах через Postgres xmin (TD-6) (concurrency)
- **feat**: persisted ImportJobRegistry в БД (TD-5) (import-jobs)
- **feat**: HTML-шаблоны MailKit + invite/weekly/low-stock джобы (P1-22) (email)
- **feat**: per-tenant журнал мутаций OrgAuditLog (P1-18) (audit)
- **feat**: оптовая отгрузка контрагенту-юрлицу (P1-5) (demands)
- **feat**: Prometheus метрики /metrics + бизнес-счётчики (P1-17) (observability)
- **feat**: GET /sync и POST /sales с двойной идемпотентностью (P1-12b) (pos-api)
- **feat**: контракты POS v1 в food-market.shared (P1-12a) (pos-shared)
- **feat**: улучшенный Swagger + TS-клиент через openapi-typescript (P1-19) (openapi)
- **feat**: ABC-анализ по Парето (P1-11) (reports)
- **feat**: отчёт «Прибыль» (выручка − COGS) (P1-10) (reports)
- **feat**: отчёт «Остатки на дату» с реконструкцией (P1-9) (reports)
- **feat**: отчёт «Продажи» с группировками и экспортом (P1-8) (reports)
- **feat**: dashboard + scheduled cleanup джобы (P1-16) (hangfire)
- **feat**: возврат поставщику (P1-7) (supplier-returns)
- **feat**: возврат от покупателя (CustomerReturn) (P1-6) (returns)
- **feat**: инвентаризация с CSV-импортом факта (P1-4) (inventories)
- **feat**: атомарное перемещение между складами (P1-3) (transfers)
- **feat**: списание со склада с указанием причины (P1-2) (losses)
- **feat**: оприходование товара без поставщика (P1-1) (enters)

## 2026-05-27

- **feat**: авто-бэкап БД+uploads — systemd timer/service + скрипт (P0-6) (deploy)
- **feat**: prod X509-ключи OpenIddict с persistent self-signed (P0-1) (auth)
- **feat**: permission-based авторизация по флагам роли (P0-5) (authz)
- **feat**: health-пробы /health/live и /health/ready (P0-4) (api)
- **feat**: rate-limit /connect/token и /api/auth/signup (P0-3) (api)

## 2026-05-26

- **fix**: change-owner требует reason ≥ 10 символов (superadmin)
- **fix**: увольнение/деактивация гасит логин связанного User (employees)
- **fix**: сериализуемое проведение приёмки против lost update остатков (supplies)
- **fix**: FK-guard удаления контрагента + валидация полей товара (catalog)
- **fix**: refresh-token rotation немедленно инвалидирует старый токен (auth)

## 2026-05-23

- **fix**: защита денег и инварианта остатков на posting-операциях (documents)
- **fix**: SuperAdmin edit-mode override обходит [Authorize(Roles=Admin)] (security)
- **fix**: чиним P0-блокеры разворачивания на чистой БД (migrations)

## 2026-05-18

- **fix**: обновить node:20-alpine → 22-alpine (pnpm 11 требует Node ≥22) (docker)
- **fix**: validatePassword проверяет заглавную и цифру (соответствует хинту) (validation)
- **fix**: onBlur валидация через e.target.value, ре-валидация вместо сброса ошибки в onChange (signup)

## 2026-05-17

- **feat**: onBlur валидация полей во всех формах (ux)

## 2026-05-08

- **fix**: блок пустого Draft на UI + бэк уже отказывает (retail-sale)
- **feat**: системная ProductGroup «Все товары» при создании org (bootstrap)
- **fix**: обязательные FK-Guid проверяются на 400 + DbUpdateException → 400 (validation)
- **fix**: блок overselling в Post — 409 если qty>остатка (retail-sale)
- **fix**: добавить [Migration] атрибут для Phase5c — без него Migrate() не находит миграцию (migrations)
- **fix**: серверная KZ-ФЛК на всех endpoint'ах принимающих phone (phone)
- **fix**: Cashier/Storekeeper больше не видят /api/organization/employees + Identity-роль маппится из orgRole (auth)
- **feat**: infrastructure + first full-cycle scenario + baseline report (e2e)

## 2026-05-06

- **feat**: forgot/reset password — endpoints + UI + IP rate-limit (auth)
- **feat**: UI /super-admin/platform-settings + тестовая отправка (platform)
- **feat**: IEmailSender + MailKit + PlatformSettingsController (platform)
- **feat**: PlatformSettings entity + миграция (singleton SMTP-конфиг) (platform)
- **feat**: фильтр sidebar и route-guard по ролям пользователя (roles)
- **feat**: двухступенчатое удаление — «уволить» → «удалить» (employees)
- **feat**: TextInput с type=email — авто-pattern для TLD-проверки (forms)
- **feat**: MoneyInput для поля «Оклад» в карточке сотрудника (forms)
- **feat**: убрать «ИНН» из UI — РК использует ИИН/БИН (localization)
- **feat**: системная роль — read-only форма прав вместо alert (roles)
- **feat**: три системные роли — Admin/Cashier/Storekeeper (roles)

## 2026-05-03

- **fix**: сохранять позицию курсора после нормализации (phone)
- **fix**: нативное редактирование, фильтр не-цифр через onBeforeInput (phone)
- **fix**: редактирование на месте курсора, как в обычном поле (phone)
- **fix**: полностью переписать на простую модель — цифры как single source of truth (phone)
- **fix**: блокировать ввод не-цифр на уровне keyDown (phone)
- **fix**: не считать «7» из префикса как введённую цифру (phone)
- **feat**: единый PhoneInput с зашитым «+7» и ФЛК Казахстана (phone)
- **feat**: телефон обязателен + ФЛК Казахстана (77XXXXXXXXX) (signup)
- **fix**: убрать «моргание» при клике на орг — переход теперь по double-click (super-admin)

## 2026-05-02

- **fix**: docker-public — актуализировать PUBLIC_*_URL под новые домены (ci)
- **fix**: кнопка «Войти» вела на 410-Gone zat.kz (public)
- **feat**: новый логотип food-market wordmark + apple mark (brand)

## 2026-04-30

- **feat**: миграция на food-market.kz / admin.food-market.kz (domains)

## 2026-04-28

- **feat**: полное управление сотрудниками любой орги (super-admin)
- **feat**: AsyncSelect — серверный поиск в дропдаунах вместо pageSize=500 (ui)
- **fix**: SuperAdmin платформы без OrganizationId + отдельный Admin для Demo Market (auth)

## 2026-04-27

- **feat**: главный администратор — терминология + защита роли/активности (employees)
- **feat**: бейдж «Владелец» + блокировка удаления с объяснением (employees)
- **fix**: пароль/orphan signup/tenant-guard toast/dashboard счётчик
- **fix**: нейтральный placeholder в поле названия организации (public)
- **fix**: закрыть критические дыры — orphan login, self-delete, owner-delete, override-баннер (auth)
- **feat**: русская локализация и строгий email с TLD (validation)
- **fix**: убрать русские имена/ИП из placeholder регистрации (public)

## 2026-04-26

- **feat**: Phase 6 — публичный сайт на food-market.zat.kz, админка на app. (deploy)
- **feat**: Phase 6 — публичный маркетинговый сайт food-market.public на Astro (public)
- **feat**: настраиваемый retention period для архивных орг (super-admin)
- **fix**: убрать цикл редиректа, регресс override после пакета задач (super-admin)
- **fix**: Phase4d таблица называется units_of_measure, не units (migration)
- **feat**: двухуровневые справочники Группы и Ед.измерения (системные + tenant) (directories)
- **feat**: системные роли read-only + русские имена + чистка дубликата у admin (roles)
- **feat**: перенести справочник Стран в системную консоль (super-admin)
- **fix**: SuperAdmin override должен применять tenant filter выбранной орги (tenancy)
- **feat**: рабочий quick-switch + UI-блокировка мутаций в read-only (super-admin)
- **feat**: Phase 2b — отдельный SuperAdminLayout и разделение от tenant-админки (super-admin)
- **feat**: Phase 3 — edit-mode с reason + audit-trail (super-admin)
- **feat**: Phase 2 — read-only «открыть как…» context switch (super-admin)
- **feat**: /quiet и /loud команды для управления PreToolUse прогресс-лентой (bridge)
- **fix**: новая org через UI получает полный bootstrap (как Demo) (super-admin)
- **feat**: PreToolUse hook for Telegram progress feed + rate-limited batching (infra)
- **fix**: grant SuperAdmin role to admin@food-market.local (seed)
- **feat**: super-admin section + setup wizard + auto-redirect (web)
- **feat**: super-admin endpoints (orgs CRUD + setup-status + audit-log + dashboard) (api)
- **feat**: Organization.IsArchived/AccountOwner + SuperAdminAuditLog + migration (domain)
- **feat**: add Salary, TaxNumber, Description, ImageUrl + radio role picker (employee)
- **feat**: permissions matrix grouped by section + clone-from-template flow (roles)
- **fix**: keep only Admin + Cashier as system, demote others to custom + migration (roles)
- **feat**: event-driven Telegram bridge — webhook + Stop hook (infra)
- **fix**: drop Employee.Navigation(RetailPointAssignments) to fix snapshot order (migrations)
- **feat**: welcome dashboard with first-steps cards (onboarding)
- **feat**: Employees + Roles pages with permissions matrix (web)
- **feat**: EmployeesController + EmployeeRolesController + invite-with-temp-password (api)
- **feat**: system roles per organization + map admin → Employee (seed)
- **feat**: Employee, EmployeeRole, RolePermissions entities + migration (domain)
- **fix**: dropdown opens as floating overlay (Portal + absolute) (searchable-select)
- **fix**: theme styles + default to today for new docs (date-field)
- **feat**: replace native input with react-datepicker — polished UX (date-field)
- **fix**: polish calendar UX — dropdown nav, today/clear footer, ru weekdays (date-field)
- **fix**: compact calendar popup — shadcn-style sizing (date-field)
- **fix**: cap width + ru locale + DD.MM.YYYY format (date-fields)
- **fix**: show both article and barcode in line subtitle (supply-lines)
- **fix**: sticky input at viewport bottom + auto-scroll on add (supply-quick-add)
- **fix**: dropdown opens upward + show only N results + create-new at bottom (supply-quick-add)
- **feat**: drop supplier field, reorder sections, add cost column (product-card+list)
- **fix**: keep input focused after scan / clear on add (supply-quick-add)
- **fix**: dropdown not rendering — Portal + fixed position (supply-quick-add)
- **feat**: inline line quick-add — scanner + autocomplete + create-on-fly (supply)
- **feat**: products quick-search + by-barcode endpoints (api)
- **fix**: колонка «Розничная» использует имя системного PriceType (supply)
- **feat**: «Проведено» внутри формы + обязательная дата и ≥1 позиция (supply)
- **fix**: catch-up Phase3b_AddShowDescriptionOnProduct (migrations)
- **feat**: inline-create option in searchable Select (ui)
- **feat**: searchable Select component (drop-in) (ui)
- **feat**: drop ShelfLifeDays + recompose classification + auto-article + barcode trash hide (product-card)
- **fix**: IsRequired применяется сразу, без перезагрузки страницы (price-types)

## 2026-04-25

- **fix**: человечная ошибка 400 + блок Save при незаполненных IsRequired ценах (product-edit)
- **fix**: correct is-system seeder + require value > 0 + system-price filter/sort (price-types)
- **feat**: inputs по справочнику PriceType — без dropdown'a (product-prices)
- **feat**: компонент + inline-наценка в таблице групп (percent-input)
- **feat**: срок годности (shelfLifeDays) + фильтр от/до (product+filters)
- **feat**: чекбокс «Проведено» с confirm + системная розничная в списке (supply+products-list)
- **feat**: drop IsActive, add ShelfLifeDays, restore PriceType IsSystem/IsRequired (phase3b)
- **feat**: supply line retail override column (web)
- **feat**: price types CRUD visibility + group markup table (web)
- **feat**: product card pricing UI + settings toggles (web)
- **feat**: recalc-retail endpoint + 30-day reference price refresh job (api)
- **feat**: supply posting hook for cost & markup (api)
- **feat**: pricing model rename and new fields (Phase3a) (domain)
- **fix**: merge barcodes/prices по ключу + 409 на concurrency (products/update)
- **fix**: toFixed(2) при allowFractional=true для правильного отображения (money-input)
- **fix**: сохранять промежуточный ввод точки в draft (money-input)
- **fix**: корректное обновление allowFractionalPrices без перелогина (money-input)
- **fix**: уважать AllowFractionalPrices в формах редактирования (money-input)
- **feat**: pre-check на Create/Update + warnings импорта + admin endpoint (barcode-uniqueness)
- **feat**: AllowFractionalPrices — переключатель дробных цен (org-settings)
- **feat**: группа обязательна, ≥1 штрихкод, умные дефолты на новом (product)
- **feat**: MoneyInput/NumberInput + select-пагинация + Range на бэкенде (forms)

## 2026-04-24

- **feat**: авто-генерация числового артикула при создании (products)
- **feat**: настройка ShowMinMaxStock для мин/макс остатков (org-settings)
- **feat**: галки «Услуга»/«Маркируемый» скрываются по умолчанию (org-settings)
- **feat**: авто-генерация EAN-13 при добавлении штрихкода (barcode)
- **feat**: server-side sort by column header click (tables)
- **feat**: валюта read-only, тянется из страны (как НДС) (org-settings)
- **feat**: ставка в стране + опц. переопределение на товаре (vat)
- **feat**: загрузка на диск сервера + галерея с лайтбоксом (product-images)
- **feat**: enum Packaging (штучный/весовой/разливной) вместо IsWeighed (product)
- **feat**: Country↔Currency, Organization.DefaultCurrency/MultiCurrency/DefaultVat + UI настроек (org-settings)
- **fix**: сделать Token опциональным (other-system/test)

## 2026-04-23

- **feat**: async jobs с прогрессом + токен в настройках (other-system-import)
- **fix**: per-page retry + чаще SaveChanges (other-system/import)
- **feat**: tree-of-groups + фильтры как в OtherSystem (catalog/products)
- **feat**: import archived entities too (as IsActive=false) (other-system)
- **fix**: reconcile stage schema — drop TrackingType, add IsMarked (db)
- **feat**: temp cleanup buttons + fix OtherSystem import duplicates (admin)
- **feat**: strict OtherSystem schema — реплика потерянного f7087e9
- **fix**: убираем выдумку Kind полностью — у OtherSystem этого поля нет (other-system)
- **fix**: не выдумывать Kind=Both для импортированных контрагентов (other-system)
- **feat**: Telegram <-> tmux bridge + local docker-registry unit (ops)
- **feat**: sales chart + KPIs (как «Показатели» в сторонняя система) (dashboard)

## 2026-04-22

- **fix**: bootstrap admin + demo org on stage/prod too, not just Dev (seeder)
- **fix**: always apply EF migrations on startup, not only in Development (api)
- **fix**: widen Article + Barcode.Code to 500 chars for real-world catalogs (catalog)

## 2026-04-21

- **fix**: accept fractional prices (decimal, not long) in DTOs (other-system)
- **fix**: add User-Agent header + enable HTTP auto-decompression (other-system)
- **fix**: drop Accept-Encoding: gzip to avoid JSON parse failure (other-system)
- **fix**: set Accept header as raw string to bypass .NET normalization (other-system)
- **fix**: exact Accept header value per OtherSystem requirement (code 1062) (other-system)
- **fix**: trailing slash on BaseUrl so HttpClient keeps /1.2/ in path (other-system)
- **fix**: OtherSystem admin endpoint uses policy-based auth on role claim directly (auth)
- **fix**: return 401 instead of 302 for API challenges; persist dev signing key across restarts (auth)
- **fix**: drop FM square badge from Logo; better 404 diagnostics on OtherSystem page (web)
- **feat**: rebrand to FOOD MARKET green (#00B207) per mobile app logo (web)
- **fix**: remove TanStack devtools palm icon; restore user profile on dashboard (web)
- **fix**: pin API dev port to 5081 (match Vite proxy config)

