aegida-console / docs / superpowers / specs / 2026-07-26-corporate-ai-chat-design.md
2026-07-26-corporate-ai-chat-design.md
Raw

Корпоративный интерфейс чата с ИИ

Дата: 2026-07-26

Цель

Создать первую рабочую версию корпоративного интерфейса для общения с ИИ-моделями и будущими агентами. По структуре и поведению интерфейс должен быть знаком пользователям ChatGPT, использовать компоненты shadcn и не зависеть от особенностей конкретного провайдера моделей.

Объём первой версии

Первая версия включает:

  • экран входа с одним тестовым пользователем;
  • JWT-аутентификацию через заголовок Authorization;
  • адаптивный интерфейс чата для настольных и мобильных экранов;
  • создание нового чата и локальную историю диалогов;
  • выбор маршрута ChatGPT, DeepSeek или Qwen;
  • отправку сообщений, потоковое отображение ответа и остановку генерации;
  • копирование ответа и повторную отправку последнего запроса;
  • единый серверный адаптер для будущего AI Gateway;
  • демонстрационный потоковый транспорт для работы без развернутого Gateway;
  • понятные состояния загрузки, пустого чата, отсутствующей конфигурации и сетевой ошибки.

В первую версию не входят корпоративный каталог пользователей, регистрация, восстановление пароля, досрочный отзыв JWT, серверное хранение истории, загрузка файлов, поиск по документам, голосовой режим, управление агентами и административная панель.

Пользовательский интерфейс

Экран входа

До открытия чата приложение проверяет сохраненный JWT. Во время проверки показывается нейтральный полноэкранный индикатор загрузки, поэтому форма входа не появляется даже на мгновение у уже авторизованного пользователя.

Если валидного JWT нет, приложение показывает отдельный экран входа с названием продукта, полями электронной почты и пароля, кнопкой входа и областью для общей ошибки. Карточка входа использует ту же типографику, палитру и shadcn-компоненты, что и основной интерфейс.

Для локальной первой версии используется тестовый пользователь:

  • электронная почта: demo@ai-control.local;
  • пароль: Demo1234!.

Значения тестовых учетных данных задаются серверными переменными окружения. Пароль не включается в клиентскую сборку и не выводится автоматически на экран входа.

Общая компоновка

Экран состоит из боковой панели и основной области чата.

Боковая панель содержит название продукта, кнопку нового чата, список недавних диалогов и компактный блок профиля-заглушки. На узких экранах панель открывается как выезжающее меню.

В верхней части основной области расположен селектор модели. Центральная область показывает пустое приветственное состояние или ленту сообщений. В нижней части закреплен композер с многострочным вводом, кнопкой отправки и кнопкой остановки во время генерации.

Визуальный стиль — спокойный корпоративный минимализм: светлая нейтральная палитра, мягкие границы, умеренные скругления, типографика Geist, shadcn-компоненты и иконки Lucide. Интерфейс повторяет знакомую информационную архитектуру ChatGPT, но не копирует брендинг OpenAI.

Поведение

  • Enter отправляет сообщение, Shift+Enter добавляет новую строку.
  • Пустое сообщение отправить нельзя.
  • После отправки текст пользователя сразу появляется в ленте.
  • Ответ ассистента добавляется частями по мере поступления потока.
  • Во время генерации пользователь может остановить запрос.
  • При смене модели новый выбор применяется к следующим сообщениям текущего чата.
  • Новый чат начинается с выбранной в данный момент моделью.
  • Название диалога формируется из первого пользовательского сообщения.
  • История и выбранная модель сохраняются в localStorage только на текущем устройстве и изолируются ключом идентификатора пользователя.
  • Выход удаляет JWT и пользовательское состояние из памяти приложения, после чего показывает экран входа.

Модель данных

Модель представляется конфигурацией интерфейса:

type ModelOption = {
  id: "chatgpt" | "deepseek" | "qwen";
  name: string;
  description: string;
};

Диалог содержит идентификатор, название, выбранный modelId, время обновления и массив сообщений. Сообщение содержит идентификатор, роль user или assistant, текст, время создания и необязательное состояние ошибки.

Отображаемые модели являются маршрутами AI Gateway. В приложении нет сведений о базовых URL, API-форматах или ключах отдельных провайдеров.

Архитектура

Аутентификация

POST /api/auth/login принимает электронную почту и пароль. Сервер сравнивает их с AUTH_EMAIL и AUTH_PASSWORD, не раскрывая клиенту, какое именно поле неверно. При успехе сервер подписывает JWT секретом JWT_SECRET и возвращает его в JSON.

JWT подписывается алгоритмом HS256 и содержит только sub, email, iat и exp. Срок между iat и exp равен 24 часам. Токен не обновляется автоматически: он остается неизменным до выхода или истечения срока и переживает перезапуск браузера благодаря localStorage.

Клиент хранит JWT под ключом ai-control-center:auth-token и добавляет его ко всем защищенным запросам:

Authorization: Bearer <JWT>

При загрузке приложения клиент читает токен и вызывает GET /api/auth/me. Пока проверка не завершена, ни вход, ни чат не отображаются. Валидный ответ открывает чат; ответ 401 удаляет токен и открывает вход.

GET /api/auth/me и POST /api/chat проверяют наличие Bearer-заголовка, подпись, алгоритм, срок действия и обязательные поля JWT. Защита API всегда выполняется на сервере и не полагается на состояние интерфейса.

Поскольку обычная загрузка страницы браузером не позволяет приложению добавить произвольный заголовок, HTML-оболочка остается доступной без авторизации. Пользовательские данные и возможности чата становятся доступны только после проверки JWT через защищенный API.

Клиент

Клиентская страница отвечает за состояние чатов, модель, ввод, потоковый ответ и локальное сохранение истории. UI-компоненты разделяются по назначению: боковая панель, селектор модели, лента сообщений, сообщение, пустое состояние и композер.

Клиент обращается только к внутреннему маршруту POST /api/chat, добавляя пользовательский JWT в Authorization, и не получает адрес или ключ AI Gateway.

Серверный маршрут

POST /api/chat принимает нормализованный запрос:

type ChatRequest = {
  model: "chatgpt" | "deepseek" | "qwen";
  messages: Array<{
    role: "user" | "assistant";
    content: string;
  }>;
};

Маршрут проверяет структуру запроса, вызывает единственный GatewayAdapter и возвращает клиенту поток текста. Клиентский контракт не меняется при добавлении новых провайдеров внутрь будущего Gateway.

GatewayAdapter

Адаптер имеет один интерфейс: принимает нормализованный запрос и возвращает ReadableStream<Uint8Array>. Реализация выбирает транспорт по серверной конфигурации:

  • если задан AI_GATEWAY_URL, запрос передается по HTTP в будущий Gateway;
  • если задано AI_GATEWAY_MOCK=true, используется детерминированный потоковый ответ без внешнего вызова;
  • если не настроен ни один транспорт, маршрут возвращает контролируемую ошибку конфигурации.

Для HTTP-транспорта используются AI_GATEWAY_URL и необязательный AI_GATEWAY_API_KEY. Ключ никогда не сериализуется в клиентский код. Gateway получает model как непрозрачный идентификатор маршрута.

Пользовательский JWT не передается в AI Gateway. Исходящий запрос использует отдельный AI_GATEWAY_API_KEY, если он настроен.

Контракт Gateway для первой версии:

  • POST на адрес из AI_GATEWAY_URL;
  • JSON-тело соответствует ChatRequest;
  • заголовок Authorization: Bearer <key> добавляется только при наличии ключа;
  • успешный ответ возвращается как поток UTF-8 текста;
  • отмена клиентского запроса прерывает исходящий запрос через AbortSignal.

Поток данных

Вход и восстановление сессии

  1. При старте клиент читает JWT из localStorage.
  2. При отсутствии токена сразу показывается экран входа.
  3. При наличии токена клиент запрашивает /api/auth/me с Bearer-заголовком.
  4. Сервер проверяет подпись и срок действия JWT.
  5. При успехе клиент открывает чат без промежуточного показа входа.
  6. При ошибке клиент удаляет токен и показывает вход.
  7. После успешной отправки формы входа клиент сохраняет выданный JWT и открывает чат.

Общение с моделью

  1. Пользователь выбирает модель и отправляет сообщение.
  2. Клиент добавляет сообщение в локальное состояние и вызывает /api/chat с Bearer-заголовком.
  3. Сервер проверяет JWT, затем model и массив messages.
  4. GatewayAdapter выбирает HTTP- или демонстрационный транспорт.
  5. Сервер прозрачно передает поток клиенту.
  6. Клиент постепенно обновляет сообщение ассистента и сохраняет завершенный диалог локально.
  7. При остановке генерации клиент отменяет запрос, а сервер передает отмену Gateway.

Ошибки и безопасность

  • Отсутствующий, некорректный или истекший JWT возвращает 401; клиент удаляет такой токен и показывает вход.
  • Неверная пара логина и пароля возвращает одинаковое общее сообщение без уточнения причины.
  • Неизвестная модель и некорректные сообщения возвращают 400.
  • Отсутствующая серверная конфигурация возвращает 503 с безопасным пользовательским сообщением.
  • Ошибки Gateway нормализуются; внутренние URL, ключи и необработанные ответы провайдера клиенту не раскрываются.
  • Один запрос может содержать не более 100 сообщений, не более 32 000 символов в одном сообщении и не более 128 000 символов суммарно.
  • При сетевой ошибке пользовательское сообщение остается в диалоге, сообщение ассистента получает состояние ошибки, а интерфейс предлагает повторить запрос.
  • Markdown первой версии отображается как безопасный текст с сохранением переносов строк; выполнение HTML исключено.
  • Пользовательский JWT хранится в localStorage по прямому требованию к header-based аутентификации, поэтому приложение не выполняет сырой HTML, не подключает сторонние скрипты и задает ограничивающую Content Security Policy.
  • JWT_SECRET, тестовый пароль и AI_GATEWAY_API_KEY существуют только в серверной конфигурации. В репозиторий добавляются только названия переменных и безопасные примеры без рабочего секрета.

Проверка качества

  • Модульные тесты проверяют успешный и неуспешный вход, срок JWT 24 часа, проверку подписи и отклонение истекшего токена.
  • Тесты интерфейса проверяют отсутствие вспышки формы входа при валидном сохраненном JWT, показ входа при 401 и выход.
  • Модульные тесты проверяют валидацию запроса, выбор транспорта, заголовок авторизации, потоковую передачу и нормализацию ошибок.
  • Тесты компонентов проверяют выбор модели, отправку по Enter, запрет пустого сообщения, остановку генерации и восстановление локальной истории.
  • Ручная проверка охватывает настольный и мобильный макет, длинные сообщения, пустое состояние и ошибки Gateway.
  • Перед завершением должны успешно пройти линтер, тесты и production-сборка.

Критерии готовности

  • Тестовый пользователь может войти, перезапустить браузер и не увидеть форму входа, пока JWT действителен.
  • Без валидного Bearer JWT получить данные пользователя или вызвать чат невозможно.
  • JWT имеет срок действия ровно 24 часа, не обновляется автоматически и удаляется при выходе или серверном отклонении.
  • Пользователь может создать чат, выбрать один из трех маршрутов и получить потоковый ответ.
  • Интерфейс визуально и поведенчески напоминает ChatGPT, оставаясь самостоятельным корпоративным продуктом.
  • Без Gateway приложение можно продемонстрировать в явно включенном локальном режиме.
  • Подключение будущего AI Gateway требует только настройки серверных переменных и соблюдения описанного контракта, без изменений клиентских компонентов.
  • Адрес и ключ Gateway не попадают в браузерную сборку или локальную историю.