- docs/imports.md, docs/simple-mode.md: «Food Market» → «ALL MARKET». - Перегенерированы скриншоты кассы (вход/продажа/оплата/смена/возврат) с логотипом ALL MARKET в шапке и на экране входа. - Внутренние TZ/verify-доки оставлены как историческая фиксация. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.6 KiB
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
PUT /api/super-admin/organizations/{id}/advanced-mode
Authorization: Bearer <token>
Content-Type: application/json
{ "enabled": true }
Ответ 200 OK:
{ "id": "...", "isAdvancedMode": true, "changed": true }
Повторный вызов с тем же состоянием → changed: false и запись в
аудит не делается (идемпотентность).
Переключение архивной организации → 409 Conflict.
Эндпоинт разрешён только роли SuperAdmin; админ орги получает 403.
Через SuperAdmin UI
- Открыть
/super-admin/organizations. - В списке у каждой строки колонка «Режим» — бейдж «Простой» (slate) или «Расширенный» (violet).
- В экшн-колонке рядом с «Архивировать» — иконка-искра. Клик → модалка подтверждения с описанием последствий.
- Подтверждение →
PUTна эндпоинт выше. После успеха список автоматически перегружается.
Запись в журнал
Каждое реальное переключение пишется в super_admin_audit_log:
{
"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:
{
"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, defaultfalse) — миграция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 на стейдже).