# Simple / Advanced mode Sprint 29, 2026-10-04. ALL MARKET по умолчанию работает в «простом» режиме — виден только минимальный набор функций розничного учёта, достаточный для обычного магазина у дома. «Расширенный» режим включает дополнительные модули (оптовые отгрузки, перемещения, лояльность и т.д.) и доступен только после явного включения оператором платформы (SuperAdmin). Переключатель в настройках магазина отсутствует намеренно — администратор организации не может ни включить, ни выключить расширенный режим себе сам. ## Простой режим — что видно | Раздел | Что внутри | |---|---| | **Главная** | KPI «Выручка сегодня / неделя / месяц», средний чек, график продаж, «Последние продажи», «Низкий остаток». | | **Товары** | Карточка товара без артикула (генерируется автоматически), описания, нескольких типов цен, страны происхождения, НДС-галок, «Услуги», «Маркируемый», максимального остатка. Остаются: Название, Штрихкоды, Группа, Единица измерения, Цена продажи (одна), Себестоимость (только чтение), Минимальный остаток, Фасовка (шт/вес/разливной), Фото. | | **Группы товаров** | Полный доступ. | | **Единицы измерения** | Полный доступ. | | **Контрагенты** | Единый список. Поля: Название, Тип лица, БИН/ИИН, Адрес, Телефон, Заметки. | | **Склад** | Приёмка, Оприходование, Списание, Инвентаризация, Возврат поставщику, Остатки. | | **Продажи** | Продажи (POS), Возвраты покупателей. | | **Отчёты** | Продажи, Прибыль, Остатки на дату. | | **Настройки** | Магазин, Склады, Кассы (RetailPoints), Сотрудники, Роли, ОФД, Импорт товаров (CSV / 1С / МойСклад). | | **Профиль** | Смена пароля, 2FA. | Весь интерфейс по-русски (переключателя языка нет). ## Расширенный режим — что добавляется - Оптовые отгрузки (`Demand`) - Перемещения между точками (`Transfer`) - Лояльность — программы и карты - Промокоды / акции - ABC-анализ - Аудит организации (`/audit-log`) - Несколько типов цен (не только retail) - Bulk-операции в таблицах + сохранённые пресеты фильтров - Telegram-бот владельца (ежедневная сводка) - SSO (вход через Google / Microsoft) - Выбор языка - Виджеты «Топ товаров» и «Маржа» на дашборде На карточках/документах появляются дополнительные поля из `Organization` («Описание», «Эталонная цена», «Валюта закупки», «НДС», «Услуга», «Маркируемый», «Макс. остаток»), которые управляются существующими org-level `Show*` флагами. ## Как SuperAdmin включает / выключает ### Через API ```http PUT /api/super-admin/organizations/{id}/advanced-mode Authorization: Bearer Content-Type: application/json { "enabled": true } ``` Ответ `200 OK`: ```json { "id": "...", "isAdvancedMode": true, "changed": true } ``` Повторный вызов с тем же состоянием → `changed: false` и запись в аудит **не** делается (идемпотентность). Переключение архивной организации → `409 Conflict`. Эндпоинт разрешён только роли `SuperAdmin`; админ орги получает `403`. ### Через SuperAdmin UI 1. Открыть `/super-admin/organizations`. 2. В списке у каждой строки колонка **«Режим»** — бейдж «Простой» (slate) или «Расширенный» (violet). 3. В экшн-колонке рядом с «Архивировать» — иконка-искра. Клик → модалка подтверждения с описанием последствий. 4. Подтверждение → `PUT` на эндпоинт выше. После успеха список автоматически перегружается. ### Запись в журнал Каждое реальное переключение пишется в `super_admin_audit_log`: ```json { "actionType": "EnableAdvancedMode", // или DisableAdvancedMode "organizationId": "...", "description": "Включен расширенный режим «Org Name»", "changesJson": { "before": false, "after": true }, "ipAddress": "...", "superAdminUserId": "..." } ``` Просмотр: `/super-admin/audit-log?organizationId=...` или UI «SuperAdmin → Журнал». ## Что происходит с данными при выключении **Ничего не удаляется.** Серверный фильтр `[RequiresAdvancedMode]` возвращает `403 ProblemDetails` на скрытых эндпоинтах; данные остаются в БД. При повторном включении всё снова видно и доступно без миграций и восстановлений. Пример `ProblemDetails` при 403: ```json { "type": "https://food-market.kz/errors/advanced-mode-required", "title": "Функция доступна в расширенном режиме.", "detail": "Этот раздел недоступен в простом режиме магазина. Обратитесь к администратору платформы, чтобы включить расширенный режим.", "status": 403, "instance": "/api/sales/demands", "code": "advanced-mode-required" } ``` Для UI это достаточный маркер, чтобы отличить этот 403 от обычного «нет прав» и отрисовать страницу «Недоступно в простом режиме» вместо общего сообщения. ## Как это устроено на бэкенде (кратко) - `Organization.IsAdvancedMode` (bool, default `false`) — миграция `20261004100000_Phase29a_IsAdvancedMode`. - `[RequiresAdvancedMode]` — атрибут MVC (`TypeFilterAttribute` → `AdvancedModeFilter : IAsyncAuthorizationFilter`), читает флаг по `org_id`-claim через `AppDbContext`. SuperAdmin bypass; аноним пропускается (отработает `[Authorize]`). Кэш in-memory 30 с, инвалидация после переключения. - Список скрытых контроллеров / действий — см. `docs/simple-mode-progress.md` (шаг 3). - `/api/me` расширен полем `advancedMode: boolean`. Веб: - `useMe()` отдаёт `advancedMode`. - `AppLayout.buildNav(roles, advancedMode)` фильтрует меню. - `AdvancedModeGuard` оборачивает скрытые маршруты и показывает «Недоступно в простом режиме» вместо белого экрана / 403 в консоли. - Карточка товара, контрагенты и приёмка в простом режиме прячут advanced-поля; значения существующих записей сохраняются и при переключении режима снова видны. ## Тесты - Unit: `tests/food-market.UnitTests/AdvancedModeFilterTests.cs` (6/6). - Integration: `tests/food-market.IntegrationTests/AdvancedModeTests.cs` (7/7). - E2E: `tests/e2e/scenarios/stage-simple-mode.yml` (7/7 на стейдже).