> ## Documentation Index
> Fetch the complete documentation index at: https://omniflow-vpn.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 0005 — Клиентская и операторская поверхности — одно приложение

> Почему /admin и клиентская панель делят проект Next.js и систему компонентов и как они остаются раздельными там, где это важно

**Статус:** принято.

## Контекст

У Omniflow две веб-аудитории, у которых почти нет ничего общего. Клиент смотрит,
сколько дней осталось, и покупает продление. Оператор возвращает платёж, разбирает
совпадение по списку блокировок и правит версию тарифа. Очевидная структура — два
фронтенд-проекта, и она была отвергнута.

Два проекта — это два конвейера сборки, два набора зависимостей, которые нужно
держать на одной версии React, два шлюза доступности, две настройки локализации
и — самое дорогое — две системы компонентов, которые начинаются одинаковыми и
расходятся. Кнопка, которая не совсем та же кнопка, — мелочь; диалог
подтверждения, который не совсем тот же диалог подтверждения, — это то, как
разрушительное действие оказывается с более слабой защитой на одной поверхности,
чем на другой.

## Решение

Одно приложение Next.js в `apps/web` содержит клиентские маршруты и `/admin`. Обе
поверхности используют одни и те же примитивы shadcn из `packages/ui`, одни и те
же каталоги `next-intl` на русском и английском, один и тот же слой данных SWR и
один и тот же стек форм и валидации.

Они разделены ровно там, где разделение является свойством безопасности, и больше
нигде:

* **Разные префиксы API.** Клиентская панель вызывает `/v1/account`, операторская
  — `/v1/panel`. Ни одна не дотягивается до маршрутов другой, как требует
  [запись 0003](https://omniflow-vpn.mintlify.site/ru/architecture/decision-0003-contract-first-api.md).
* **Разные сессии с разным сроком жизни.** Операторские истекают после минут
  бездействия и часов в абсолютном исчислении; клиентские живут днями, потому что
  повторный вход стоит оператору секунд рабочего дня, а клиент, которого
  разлогинило за обедом, просто вернётся в бот. Построение токена общее, чтобы
  реализация и дисциплина хранения были одни; применяемая к нему политика — нет.
* **Разные модели авторизации.** Операторская поверхность закрыта RBAC на
  серверной границе, поэтому оператор без права доступа не получает саму
  страницу. У клиентской поверхности ролей нет вовсе — она отдаёт только
  собственные данные клиента.

## Последствия

Изменение оформления попадает сразу на обе поверхности — в этом и смысл, — и это
же означает, что неосторожное изменение попадает сразу на обе. Общие примитивы и
рецензируются как общие: правка контраста, затемнившая токены subtle, success и
warning, должна была пройти шлюз доступности и на уже существовавших
операторских страницах, а не только на новых клиентских.

Между аудиториями не разделяется бандл в том смысле, за который платит клиент:
разбиение кода по маршрутам держит операторские экраны вне первой загрузки
клиента, а бюджет производительности JavaScript закреплён по маршрутам с потолком
на область, а не одним общим числом.

Обе поверхности живут в одном развёртывании. Выпустить исправление клиентской
панели, не выпустив операторскую той же версии, нельзя; это следует из
[записи 0001](https://omniflow-vpn.mintlify.site/ru/architecture/decision-0001-modular-monolith.md) и является тем же
компромиссом.

## Когда пересматривать

* Поверхности требуется фреймворк, модель рендеринга или ритм выпуска, которые не
  подходят другой. Желание другого *внешнего вида* — не тот случай: система
  компонентов уже параметризована.
* Операторская панель обзаводится по-настоящему офлайновым или десктопным
  режимом, а это другой продукт, а не другой маршрут.

## Смежное

* [Панель оператора](https://omniflow-vpn.mintlify.site/ru/operations/admin-panel.md) — операторская поверхность и её граница RBAC.
* [Клиентская веб-панель](https://omniflow-vpn.mintlify.site/ru/customer/web-panel.md) — что клиент может сделать в браузере.
* [Запись 0003](https://omniflow-vpn.mintlify.site/ru/architecture/decision-0003-contract-first-api.md) — три префикса и общий транспорт.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.