Skip to content

Веб-фронтенд (frontend/) ​

Веб-фронтенд aihelpme.ru — это одностраничное приложение (SPA) на Vue 3 + TypeScript + Vite, предоставляющее весь интерфейс взаимодействия: управление базами знаний, диалоги с агентами, организационную работу, системные настройки и т. д. Один и тот же код обслуживает три формы:

  1. Стандартное веб-развёртывание: артефакт сборки Vite обслуживается контейнером nginx, /api проксируется на бэкенд;
  2. Веб-встраивание (Embed): отдельная облегчённая точка входа frontend/embed.html + frontend/src/embed-main.ts, позволяющая сторонним сайтам встраивать диалог с агентом через iframe / всплывающее окно;
  3. Настольная версия (Wails): через автоматически сгенерированные привязки в frontend/src/wailsjs/ общается с Go-стороной настольного процесса, поддерживает область перетаскивания --wails-draggable, синхронизацию светлой/тёмной темы окна и другие настольные функции.

Обзор технологического стека ​

Согласно frontend/package.json (версия 0.8.3):

КатегорияВыборВерсияОписание
ФреймворкVue^3.5.34Composition API, стиль <script setup>
ЯзыкTypeScript~6.0.3Проверка типов через vue-tsc (npm run type-check)
Сборочный инструментVite^7.3.5Плагины: @vitejs/plugin-vue, @vitejs/plugin-vue-jsx
Библиотека UI-компонентовTDesign (tdesign-vue-next)^1.19.2Вместе с tdesign-icons-vue-next 0.4.4 (версия зафиксирована через overrides)
Управление состояниемPinia^3.0.4Все store находятся в frontend/src/stores/
МаршрутизацияVue Router^4.5.0createWebHistory, см. frontend/src/router/index.ts
Мультиязычностьvue-i18n^11.4.2zh-CN / en-US / ru-RU / ko-KR / ja-JP
HTTPaxios^1.16.0Единый экземпляр инкапсулирован в frontend/src/utils/request.ts
SSE-поток@microsoft/fetch-event-source^2.0.1Потоковые ответы в чате, см. frontend/src/api/chat/streame.ts
Рендеринг Markdownmarked / marked-katex-extension / katex / highlight.js / mermaid—Форматированный вывод ответов в чате (формулы, подсветка кода, диаграммы)
Безопасностьdompurify^3.4.11Единая санитизация содержимого v-html (frontend/src/utils/markdownDomPurify.ts)
Предпросмотр документовdocx-preview / @vue-office/pptx / xlsx / papaparse—Предпросмотр Word / PPT / Excel / CSV на сайте
Длинные спискиvue-virtual-scroller2.0.0-beta.8Виртуальная прокрутка списка сообщений
СтилиLess + CSS Variablesless ^4.6.4Переменные темы см. в frontend/src/assets/theme/theme.css

Примечательные детали зависимостей:

  • xlsx устанавливается версии 0.20.2 с официального фиксированного адреса SheetJS, package-lock.json сохраняет контрольные суммы целостности; репозиторий исходников не содержит пакетов компонентов, для офлайн-сборки нужно заранее подготовить кэш npm;
  • frontend/pnpm-workspace.yaml не объявляет workspace дочерних пакетов, а содержит только белый список allowBuilds (разрешающий @vue-office/pptx, esbuild, vue-demi выполнять сборочные скрипты) — для политики безопасности сборочных скриптов pnpm;
  • В overrides / resolutions отключён lightningcss и унифицированы версии esbuild, serialize-javascript.

Структура модулей ​

Краткий обзор каталогов ​

КаталогНазначение
frontend/src/main.tsТочка входа основного SPA: устанавливает TDesign / Pinia / Router / i18n, инициализирует тему и шрифт, регистрирует офлайн-защиту иконок TDesign (installTDesignIconOfflineGuard, чтобы избежать запросов к tdesign.gtimg.com во время работы), ждёт router.isReady() перед монтированием, чтобы избежать мигания первого экрана
frontend/src/embed-main.tsТочка входа встраивания: отдельное приложение Vue и отдельная маршрутизация (только /embed/:channelId), монтируется в #embed-app, использует отдельный i18n (src/i18n/embed.ts)
frontend/src/views/Компоненты уровня страниц, разбитые по каталогам по бизнес-доменам (см. таблицу маршрутов ниже)
frontend/src/components/Общие компоненты для страниц (пузыри сообщений, оверлей загрузки, командная палитра и т. д.)
frontend/src/stores/Состояние Pinia (см. таблицу store ниже)
frontend/src/api/Обёртка API бэкенда (см. таблицу модулей API ниже)
frontend/src/composables/Композиционные функции: тема, шрифт, обработка потока чата, всплывающий слой ссылок, мост Embed и др.
frontend/src/hooks/Бизнес-хуки (например, useKnowledgeBase)
frontend/src/utils/Набор утилит: экземпляр axios, конвейер рендеринга markdown, санитизация DOMPurify, отображение инструментов агента и др.
frontend/src/i18n/Конфигурация vue-i18n и языковые пакеты
frontend/src/assets/theme/CSS-переменные темы (light / dark)
frontend/src/wailsjs/Автоматически сгенерированные привязки настольного приложения Wails (не редактировать вручную)
frontend/src/directives/, frontend/src/types/, frontend/src/config/Пользовательские директивы, определения типов, конфигурация
frontend/public/Статические ресурсы: weknora-widget.js (загрузчик для встраивания на сторонних сайтах), config.js (заглушка конфигурации времени выполнения, перезаписывается при запуске контейнера), офлайн-иконки TDesign

Список маршрутов страниц ​

Маршруты определены в frontend/src/router/index.ts, используется createWebHistory; все компоненты страниц загружаются динамическим import (ленивая загрузка с разбиением по маршрутам).

Маршруты верхнего уровня ​

ПутьИмяКомпонентФункция
/—ПеренаправлениеПеренаправляет на /platform/knowledge-bases
/loginloginsrc/views/auth/Login.vueСтраница входа (с OIDC, переключением языка, анимированным фоном)
/registerregisterByInvitesrc/views/auth/Login.vueСтраница регистрации по приглашению — переиспользует компонент Login, при монтировании проверяет ?token=xxx и переключается в режим регистрации по приглашению
/onboarding/workspaceworkspaceOnboardingsrc/views/auth/WorkspaceOnboarding.vueСтраница онбординга рабочего пространства для пользователей без тенанта (создать или дождаться приглашения); требуется вход, но наличие тенанта не обязательно
/joinjoinOrganizationПеренаправлениеСсылка-приглашение для вступления в организацию: преобразует ?code= в параметр invite_code и переходит на /platform/organizations
/knowledgeBasehomesrc/views/knowledge/KnowledgeBase.vueДетали базы знаний (устаревший путь верхнего уровня)
/platformPlatformsrc/views/platform/index.vueОсновной макет платформы (меню слева + выход маршрутизации + модальное окно глобальных настроек + оверлей drag-and-drop загрузки); по умолчанию перенаправляет на список баз знаний
/platform/dev/markdownmarkdownTestsrc/views/dev/MarkdownTestPage.vueСтраница визуального регрессионного теста рендеринга Markdown, регистрируется только в режиме разработки (import.meta.env.DEV)

Дочерние маршруты /platform ​

ПутьИмяКомпонентФункция
/platform/knowledge-basesknowledgeBaseListsrc/views/knowledge/KnowledgeBaseList.vueСписок баз знаний: боковая панель пространства (все / мои / по организации / избранное / недавние), список карточек, точка входа создания; поддерживает сортировку по времени обновления / создания / имени (components/ResourceSortControl.vue, применимо и к списку агентов)
/platform/knowledge-bases/:kbIdknowledgeBaseDetailsrc/views/knowledge/KnowledgeBase.vueДетали базы знаний: список документов (сортировка по времени обновления / создания / имени файла, сортировка выполняется на сервере, по умолчанию по времени создания по убыванию), загрузка, статус разбора, точка входа сессии, Wiki и т. д.
/platform/agentsagentListsrc/views/agent/AgentList.vueСписок и управление агентами, редактирование через AgentEditorModal.vue; требуется возможность развёртывания agents
/platform/toolbox/:section?toolboxsrc/views/toolbox/Toolbox.vueИнструментарий: три вкладки skills (навыки), mcp (службы MCP), browserconnection (подключение браузера), см. раздел «Инструментарий» ниже
/platform/artifactsartifactLibrarysrc/views/artifacts/ArtifactLibrary.vueБиблиотека артефактов: сводит файлы, созданные агентами в разных сессиях; требуется возможность развёртывания settings.sandbox
/platform/creatChatglobalCreatChatsrc/views/creatChat/creatChat.vueСтраница создания диалога: рекомендуемые вопросы, запуск сессии после выбора баз знаний / агента / модели
/platform/knowledge-bases/:kbId/creatChatkbCreatChatsrc/views/creatChat/creatChat.vueЗапуск нового диалога из контекста конкретной базы знаний (тот же компонент)
/platform/chat/:chatidchatsrc/views/chat/index.vueСтраница сессии: поток сообщений (потоковый рендеринг SSE, скелетон, виртуальная прокрутка), панель ссылок, предпросмотр вложений
/platform/organizationsorganizationListsrc/views/organization/OrganizationList.vueСписок организаций: создание/вступление в организацию, управление участниками и общими ресурсами (вместе с OrganizationSettingsModal.vue); требуется возможность развёртывания organizations, в версии Lite всегда скрыто. При добавлении участника поиск идёт точно по полному ID пространства, а не нечёткий поиск по имени пространства
/platform/settingssettingssrc/views/settings/Settings.vueЦентр настроек (в виде полноэкранного модального окна), разделы см. в «Разделы и видимость центра настроек» ниже
/platform/tenant—ПеренаправлениеСовместимость со старым путём → /platform/settings
/platform/knowledge-search—ПеренаправлениеСтарый путь глобального поиска → список баз знаний с открытием глобальной командной палитры (⌘K) через ?cmdk=
/platform/integrations—Перенаправление→ /platform/settings?section=integration-im (старый ?tab= нормализуется в integration-<tab>; представления в src/views/integrations/)
/platform/system, /platform/system/settings, /platform/system/adminssystemSettings / systemAdminsПеренаправлениеСтарые пути системного администрирования → /platform/settings?section=system-global, требуется requiresSystemAdmin (представления в src/views/system/: SystemSettings.vue, SystemAuditLog.vue, PlatformAPIKeys.vue и др.)
/platform/system/queuessystemQueuesПеренаправление→ /platform/settings?section=runtime-queues (очереди задач времени выполнения src/views/system/RuntimeQueues.vue)

Отдельная точка входа: страница встраивания ​

/embed/:channelId не относится к маршрутам основного SPA, а образует отдельную точку входа из frontend/embed.html + frontend/src/embed-main.ts (и nginx, и dev server Vite делают fallback /embed/* на embed.html); компонент — src/views/embed/EmbedPage.vue (вместе с EmbedChatView.vue / EmbedChatCore.vue / EmbedBotMessage.vue и др.), используется аутентификация по Embed-токену, предназначена для встраивания через iframe на сторонних сайтах.

Разделы и видимость центра настроек ​

Settings.vue представляет все разделы, сгруппированные в семь групп, с навигацией по ?section=:

ГруппаРазделы (значения section)
Аккаунтgeneral (личные предпочтения), userprofile, mymemory (личная память), envvars (личные переменные)
Пространствоtenant (информация о пространстве), members (участники), chathistory, memory (память пространства)
Модели и выполнениеmodels, ollama, weknoracloud
Интеграции публикацииintegration-im, integration-embed, integration-api, integration-mcpserver, integration-cli, integration-chrome, integration-claw
Данные и расширенияvectorstore, parser, storage, sandbox, websearch
Системное администрированиеsystem-global, runtime-queues, platform-api-keys, system-audit-log
Платформаsystem (информация о версии)

Вкладки интеграций публикации регистрируются через INTEGRATION_TABS / INTEGRATION_PREVIEW_ITEMS в frontend/src/config/integrations.ts, значения разделов единообразно имеют вид integration-<tab>; старый /platform/integrations?tab=<tab> нормализуется в соответствующий раздел.

Начиная с v0.8.2 навыки, службы MCP и подключение браузера больше не являются разделами настроек, а перенесены в Инструментарий. Старые закладки /platform/settings?section=skills|mcp|browserconnection перенаправляются навигационным хуком на /platform/toolbox/<section> (для skills сохраняется параметр sandboxId).

Видимость определяется тремя наборами правил, причём фронтенд лишь сужает отображение, а авторитетом является серверный навигационный хук:

  • Порог роли в пространстве: SETTINGS_SECTION_MIN_ROLE в frontend/src/config/settingsAccess.ts задаёт минимальную роль для каждого раздела. general / models / system / userprofile / tenant / members / mymemory / envvars доступны начиная с viewer (видны только для чтения); ollama, weknoracloud, websearch, chathistory, memory, vectorstore, parser, storage, sandbox требуют admin; integration-api среди интеграций публикации требует owner (INTEGRATION_TAB_MIN_ROLE). Есть также SETTINGS_MANAGEMENT_SHORTCUT_MIN_ROLE: помеченные «управление» быстрые ссылки в меню аватара имеют более высокий порог (управление участниками требует owner, управление моделями — admin), чтобы не маскировать страницы только для чтения под точки управления.
  • Возможности развёртывания: SETTINGS_SECTION_CAPABILITY / INTEGRATION_TAB_CAPABILITY в frontend/src/config/deploymentCapabilities.ts сопоставляют разделы с ключами возможностей, возвращаемыми GET /api/v1/system/capabilities (например, settings.sandbox, integrations.mcpserver); при явном supported: false точки входа скрываются, см. «Навигация настроек и возможности развёртывания» ниже.
  • Белый список системных администраторов: SYSTEM_ADMIN_SETTINGS_SECTIONS (system-global, runtime-queues, platform-api-keys, system-audit-log) отображаются только системным администраторам, независимо от роли в пространстве; подробнее см. в разделе «Системный администратор и консоль платформы» файла Тенанты, пользователи и аутентификация/авторизация.

Инструментарий ​

Пункт «Инструментарий» в меню слева (/platform/toolbox/:section?, src/views/toolbox/Toolbox.vue) централизованно управляет инструментами, доступными агентам; вкладки определены в TOOLBOX_ITEMS в frontend/src/config/toolbox.ts:

Вкладка (section)СодержимоеУсловие видимости
skillsУправление навыками (переиспользует SkillSettings.vue), можно с ?sandboxId= для перехода к конфигурации песочницыначиная с admin, и развёртывание поддерживает settings.sandbox
mcpСлужбы MCP (переиспользует McpSettings.vue)начиная с admin, и развёртывание поддерживает settings.mcp
browserconnectionПодключение браузера (переиспользует BrowserConnectionSettings.vue), на вкладке отображается статус подключенияначиная с viewer

Вкладки наследуют пороги роли и возможностей развёртывания прежних разделов настроек (canAccessToolboxSection); если в текущем пространстве нет ни одной видимой вкладки, показывается пустое состояние. При наведении на пункт меню боковой панели предпросматриваются доступные инструменты, статус подключения браузера также отображается в боковой панели. Использование подключения браузера см. в Локальный браузер.

Разделы модального окна редактирования базы знаний ​

Многие настройки находятся не в центре настроек, а в модальном окне редактирования базы знаний (KnowledgeBaseEditorModal.vue), так как действуют на уровне базы. Разделы боковой панели сгруппированы в пять групп, три из которых появляются только при «редактировании существующей базы знаний»:

ГруппаРазделы (key)Примечание
Основныеbasic, modelsИмя, тип, модели диалога/векторов/резюме
Обработкаparser, multimodal, asr, chunkingДвижок разбора и заголовок первой строки, понимание изображений, транскрипция речи, параметры разбиения на блоки
ДанныеvectorStore, storage, faqfaq — только для баз типа FAQ; vectorStore после привязки изменить нельзя
ИнтеграцииdatasourceТолько в режиме редактирования; синхронизация Feishu / Lark (база знаний и облачный диск), Notion, Confluence, Yuque, документов DingTalk, IMA, RSS / Atom, GitLab и др. настраивается здесь, а не в глобальных настройках (определения коннекторов см. в views/knowledge/settings/DataSourceEditorDialog.vue)
Управлениеgraph, advanced, share, activityГраф знаний, расширенные параметры, публикация в организацию, лента активности; последние две — только в режиме редактирования

Глобальная командная палитра (⌘K / Ctrl+K) ​

components/GlobalCommandPalette.vue — второй основной путь навигации помимо боковой панели:

  • Поиск по базам знаний, документам и сессиям, с возможностью сузить область до конкретной базы знаний (scope chip) перед поиском;
  • В пустом состоянии показываются недавние поиски и быстрые действия (создать базу, загрузить, создать сессию и т. д.);
  • Точка входа в правом верхнем углу открывает панель настроек поиска (views/settings/RetrievalSettings.vue). Здесь настраиваются TopK, пороги векторов/ключевых слов, параметры переранжирования — она не в центре настроек; если не можете найти, она здесь.

Навигационные хуки ​

В router.beforeEach реализована полная цепочка аутентификации/авторизации (frontend/src/router/index.ts):

  1. Пропуск обратного вызова OIDC: если hash URL содержит oidc_result= / oidc_error=, пропуск выполняется напрямую, а обработка передаётся App.vue;
  2. Старые закладки инструментария: /platform/settings?section=skills|mcp|browserconnection перенаправляются на /platform/toolbox/<section>;
  3. Восстановление глубоких ссылок Lite / настольного приложения: при жёстком обновлении в режиме Lite, попадающем на домашнюю страницу по умолчанию, из sessionStorage восстанавливается последний посещённый подпуть /platform (кроме страницы организации);
  4. Восстановление сессии: если пользователь не вошёл, сначала через weknora_token из localStorage вызывается getCurrentUser() для восстановления сессии (одновременно обновляются memberships, чтобы избежать задержки изменений ролей);
  5. Автоматический вход в настольном приложении: при неудачном восстановлении однократно выполняется autoSetup(). Начиная с v0.8.2 он действует только в нативном настольном приложении: сначала через привязку Wails GetAutoSetupToken() получаются случайные учётные данные текущего процесса, затем с заголовком X-WeKnora-Desktop-Token вызывается POST /api/v1/auth/auto-setup; в версии Lite, открытой в браузере, такой привязки нет, поэтому используется обычная регистрация / вход. При неудаче в localStorage ставится метка, чтобы избежать повторных попыток;
  6. Порог тенанта: пользователь вошёл, но нет действующего тенанта → переход на /onboarding/workspace;
  7. Порог возможностей развёртывания: если meta.requiredCapability маршрута (например, agents, organizations, settings.sandbox) не поддерживается текущим развёртыванием, после уведомления выполняется возврат к списку баз знаний; при неудачном определении возможностей пропуск, а окончательную проверку выполняет интерфейс бэкенда;
  8. Порог SystemAdmin: маршруты с requiresSystemAdmin для не-системных администраторов перенаправляют обратно к списку баз знаний (блокировка только на уровне UI, на сервере есть отдельная строгая проверка).

Управление состоянием (Pinia) ​

Store и вспомогательные модули в frontend/src/stores/:

ФайлStore ID / типНазначение
stores/auth.tsuseAuthStoreЯдро аутентификации: user / token / refreshToken / tenant / memberships / определение роли (hasRole, isSystemAdmin), флаг режима Lite; при выходе каскадно очищает кэш уровня пространства других store и перезагружает предпочтения пользователя (тема/шрифт)
stores/chatResources.tsuseChatResourcesStoreКэш ресурсов уровня пространства (TTL 60s): списки баз знаний, агентов, моделей, провайдеров веб-поиска, переиспользуется селекторами чата/создания диалога
stores/editorResources.tsuseEditorResourcesStoreКэш ресурсов редактора/настроек (TTL 60s): конфигурация и статус движков хранилища, шаблоны промптов, движки разбора, системная информация, службы MCP, навыки, пресеты типов агентов, конфигурация поиска
stores/commandPalette.tsuseCommandPaletteStoreПереключатель и запросы глобальной командной палитры (⌘K / Ctrl+K); недавние поиски хранятся в области (user, tenant), чтобы избежать утечки между аккаунтами
stores/organization.tsuseOrganizationStoreОрганизационная работа: список организаций, участники, общие базы знаний/агенты, заявки на вступление и их проверка, повышение роли — полный набор действий
stores/organizationState.tsМодуль чистых функцийЧистая логика upsert / merge списка организаций, влияние проверки вступления на число участников и др. (с юнит-тестом organizationState.test.ts)
stores/settings.tsStore настроекКонфигурация сессии и агента: выбранные базы знаний/файлы/теги/MCP/навыки/инструменты, конфигурация моделей, конфигурация Ollama, переключатель веб-поиска и т. д.
stores/settingsStorage.tsМодуль чистых функцийЧтение, клонирование и исправление встроенных режимов агента при сохранении настроек (ключ WeKnora_settings) (с settingsStorage.test.mjs)
stores/menu.tsuseMenuStoreСтруктура меню навигации слева (пункты создания диалога, баз знаний, агентов и др.) и заголовки i18n
stores/knowledge.tsknowledgeStoreСписок карточек знаний и их общее число (облегчённый)
stores/ui.tsuseUIStoreГлобальное состояние UI: модальное окно настроек, модальное окно редактирования базы знаний, редактор ручных документов, сворачивание боковой панели — переключатели и параметры
stores/uploadConfirm.tsStore подтверждения загрузкиСостояние диалога подтверждения параметров обработки перед загрузкой / импортом по URL / ручным вводом / повторным разбором
stores/versionedRequest.tsМодуль чистых функцийcreateVersionedRequestCoordinator: координатор кэшированных запросов с версией, предотвращающий перезапись новых данных старыми ответами (с versionedRequest.test.ts)
stores/deploymentCapabilities.tsuseDeploymentCapabilitiesStoreСнимок возможностей развёртывания (GET /api/v1/system/capabilities), используется навигационными хуками, боковой панелью, настройками и инструментарием для определения видимости точек входа
stores/modelProviders.tsuseModelProvidersStoreКэш каталога поставщиков моделей (GET /api/v1/models/providers, загружается по типу модели); редактор моделей и карточки моделей единообразно читают информацию о поставщике отсюда
stores/uploadTasks.ts (+ uploadQueue.ts / uploadTasksCore.ts / uploadTasksState.ts)useUploadTasksStoreОчередь загрузки файлов знаний: ограничение параллельной передачи, отмена / повтор, опрос прогресса разбора, управление плавающей панелью прогресса загрузки; загрузка продолжается после ухода со страницы базы знаний
stores/browserConnection.tsuseBrowserConnectionStoreСостояние подключения локального браузера, используется вкладками инструментария и статусом боковой панели
stores/sessionActivity.tsuseSessionActivityStoreСостояние «в процессе» для сессий в боковой панели

Обёртка API (frontend/src/api/) ​

Основа запросов ​

  • Экземпляр axios: frontend/src/utils/request.ts создаёт единый экземпляр (baseURL берётся из getApiBaseUrl() в frontend/src/utils/api-base.ts, учитывает Vite BASE_URL для поддержки развёртывания с обратным прокси на подпути; тайм-аут обычных запросов 30s). Для загрузки файлов (postUpload) тайм-аут рассчитывается по размеру полезной нагрузки (uploadTimeoutMs в utils/requestTimeouts.ts, нижняя граница 5 минут, увеличение примерно на 10MB/минуту); после увеличения MAX_FILE_SIZE_MB большие файлы не прерываются значением по умолчанию 30s; явно переданный вызывающей стороной timeout имеет приоритет.
  • Перехватчик запросов: автоматически добавляет Authorization: Bearer <weknora_token> (токен Embed канала Embed не перезаписывается), Accept-Language (текущий язык i18n), X-Request-ID (случайная строка), X-Tenant-ID (доступ между пространствами; всегда передаётся id активного пространства, чтобы заголовок не терялся после переключения пространства).
  • Перехватчик ответов: 2xx распаковывается и возвращает data; 401 запускает single-flight обновление refresh token, при неудаче очередь воспроизводится; 401 публичных эндпоинтов (/auth/login, /auth/register, /auth/oidc/, /auth/auto-setup, /auth/invitations/lookup, /api/v1/embed/, то есть PUBLIC_AUTH_PATHS) выбрасывается прямо на страницу без перехода на вход; страница Embed никогда не перенаправляется на /login.
  • HTTP-код статуса ($httpStatus): возвращаемый тип get / post / put / patch / del / postUpload — WithStatus<T>; к JSON-ответу в виде объекта или массива прикрепляется неперечисляемое свойство $httpStatus, позволяющее различать результаты с одинаковой формой успеха (например, создание пользователя системным администратором: 201 означает создание, 200 — идемпотентный повтор). Оно не появляется при раскрытии объекта, JSON.stringify и Object.keys; ответы Blob, строки и SSE не имеют этого свойства.
  • SSE-поток: frontend/src/api/chat/streame.ts на основе @microsoft/fetch-event-source инкапсулирует useStream(), поддерживает потоковый вывод, состояние загрузки, состояние ошибки и отладочные метаданные запроса; выше он организуется frontend/src/composables/useChatStreamHandler.ts в поток сообщений чата. Когда рукопожатие потока чата возвращает 401, используется общий с axios single-flight из utils/authRefresh.ts; получив новый токен, запрос воспроизводится один раз как есть, поэтому истечение access token не прерывает начатый диалог.

Список модулей ​

МодульНазначение
api/auth/Вход, регистрация, OIDC, autoSetup (только нативное настольное приложение, с X-WeKnora-Desktop-Token от Wails), восстановление сессии getCurrentUser
api/tenant/ (index / members / invitations / audit-log)Информация о тенанте (рабочем пространстве), управление участниками, приглашения, журнал аудита
api/organization/CRUD организаций, участники, общие базы знаний/агенты, заявки на вступление
api/knowledge-base/CRUD баз знаний и управление файлами/записями знаний
api/chat/ (index / streame / steer / temporary-attachments)CRUD сессий, генерация заголовков, потоковый вопрос-ответ SSE, добавление сообщения в текущий раунд работающего агента (steer), временные вложения
api/artifacts.tsСписок и удаление библиотеки артефактов (/api/v1/artifacts)
api/memory.ts / api/env-vars.tsПамять пространства / личная память, личные переменные
api/mcp-endpoint.tsУправление эндпоинтами встроенного MCP Server (Интеграции публикации → MCP Server)
api/chat-history.tsИстория чата
api/agent/CRUD пользовательских агентов, пресеты типов, заполнители (включая встроенные id Quick Answer / Smart Reasoning)
api/model/Управление конфигурацией моделей
api/retrieval.tsКонфигурация поиска тенанта
api/vector-store.ts / api/storage-backend.ts / api/chunker/Конфигурация векторного хранилища, бэкенда хранилища, чанкера
api/datasource/Подключение источников данных
api/embed/Управление каналами веб-встраивания (создание каналов, ограничение частоты и т. д.)
api/initialization/Процесс инициализации системы
api/system/Системные интерфейсы: информация о системе, статус движков хранилища, шаблоны промптов, движки разбора и др.
api/mcp-service.ts / api/skill/Управление службами MCP и навыками
api/web-search.ts / api/web-search-provider.tsВеб-поиск и конфигурация провайдеров
api/wiki/Интерфейсы, связанные с генерацией Wiki базы знаний
api/message-suggestion.tsРекомендуемые вопросы
api/user-favorites.tsИзбранное пользователя (списки избранных баз знаний/агентов)

Состояние ожидания в таймлайне диалога ​

У визуального прогресса конвейера RAG (views/chat/components/RagPipelineProgress.vue) между «все видимые шаги завершены» и «модель выдаёт первое слово» есть период тишины. Этот промежуток описывает utils/rag-pipeline-state.ts:

  • getRagPipelineWaitKind() определяет тип ожидания: model (генерируется ответ) — только если шаг поиска действительно завершался; раунды без шага поиска, такие как вопрос-ответ только по вложениям, получают нейтральное preparing вместо полного отсутствия обратной связи;
  • createRagWaitController() отвечает за детали отображения: показывается с задержкой RAG_WAIT_REVEAL_DELAY_MS (250ms), чтобы избежать мигания при быстром ответе модели; после RAG_WAIT_STALL_DELAY_MS (60s) переходит в состояние «застой» — при разрыве SSE бэкенд больше не отправляет is_completed, и без этого ограничения индикатор прогресса вечно утверждал бы «уже почти готово»;
  • Изменения состояния объявляются через постоянную область aria-live, поэтому пользователи программ чтения с экрана не пропускают их из-за полной замены узла.

Мультиязычность (i18n) ​

Реализовано в frontend/src/i18n/index.ts на основе vue-i18n (режим Composition с legacy: false, globalInjection: true):

  • Поддерживаемые языки (frontend/src/i18n/locales/):
  • zh-CN (китайский упрощённый, по умолчанию и fallback)
  • en-US (английский)
  • ru-RU (русский)
  • ko-KR (корейский)
  • ja-JP (японский)
  • Выбор языка сохраняется в ключе locale в localStorage; перехватчик axios записывает текущий язык в заголовок Accept-Language, чтобы бэкенд возвращал локализованное содержимое.
  • Некоторые переводы содержат встроенные теги <strong> (после санитизации DOMPurify рендерятся через v-html); настроено warnHtmlMessage: false для отключения предупреждений HTML в vue-i18n.
  • Отдельный i18n для Embed: страница встраивания для посетителей использует отдельный frontend/src/i18n/embed.ts (загружается embed-main.ts), а тексты «Веб-встраивание» админской части остаются в основном языковом пакете; frontend/src/i18n/locales/embed/index.ts единообразно re-export-ит помощник нормализации языка (поддерживает синхронизацию языка embed из параметров URL).
  • Инструменты аудита и обрезки: языковые пакеты объёмны и легко накапливают мёртвые ключи без ссылок или непереведённые новые ключи, поэтому прилагаются три скрипта (frontend/package.json):
КомандаНазначение
npm run check-i18nЗапускает src/i18n/localeKeyAudit.test.ts, проверяя совпадение наборов ключей языковых пакетов и отсутствие недостающих ссылок
npm run scan-i18n-gapsСравнивает фактически используемые в исходниках ключи с языковыми пакетами и сообщает неопределённые и неиспользуемые ключи
npm run regenerate-i18n-localesПо результатам сканирования заново генерирует обрезанные языковые пакеты

Имена действий журнала аудита идут через отдельный реестр (i18n/auditActionRegistry.ts + auditActionLocaleDefaults.ts); при добавлении нового действия аудита достаточно добавить запись в реестр, чтобы инструменты обрезки не удалили их как неиспользуемые мёртвые ключи.

Тема и внешний вид ​

  • Режим темы: frontend/src/composables/useTheme.ts предоставляет три состояния light | dark | system. Применяется установкой атрибута theme-mode на document.documentElement; режим system отслеживает медиазапрос prefers-color-scheme и следует автоматически.
  • CSS-переменные: frontend/src/assets/theme/theme.css в системе токенов TDesign (--td-brand-color-*, --td-bg-color-*, --td-text-color-*, шрифт/радиусы/тени и т. д.) определяет два набора переменных для :root[theme-mode="light"] и :root[theme-mode="dark"]; брендовый цвет — зелёный; стили компонентов всегда ссылаются на переменные, обеспечивая смену оформления в один клик.
  • Сохранение предпочтений: предпочтения темы и шрифта через frontend/src/composables/preferenceStorage.ts сохраняются в localStorage с пространством имён по id пользователя и перезагружаются через reloadThemeFromStorage() / reloadFontFromStorage() при входе/выходе/переключении аккаунта (запускается в stores/auth.ts).
  • Шрифт: frontend/src/composables/useFont.ts управляет выбором шрифта интерфейса; main.ts при запуске выполняет initTheme() + initFont().
  • Синхронизация с настольным приложением: syncWailsNativeChrome() в useTheme.ts вызывает WindowSetDarkTheme / WindowSetLightTheme / WindowSetBackgroundColour из runtime Wails, чтобы цвет фона нативного окна соответствовал теме веб-страницы и уменьшалось белое мигание при обновлении.

Сборка и развёртывание ​

Разработка и сборка (vite.config.ts) ​

Ключевые моменты frontend/vite.config.ts:

  • Сборка с двойной точкой входа: rollupOptions.input одновременно собирает index.html (основной SPA) и embed.html (страница встраивания); в среде разработки собственный плагин embedHtmlDevFallback() переписывает запросы /embed/:channelId на /embed.html, согласуясь с поведением nginx.
  • Разделение кода на блоки: manualChunks выносит mermaid/dagre/cytoscape, marked/katex, highlight.js в vendor-mermaid, vendor-markdown, vendor-highlight соответственно; точка входа embed через modulePreload.resolveDependencies фильтрует тяжёлые чанки чата, гарантируя, что первый экран страницы встраивания загружает только код, необходимый для обмена токенами.
  • Внедрение версии: __FRONTEND_VERSION__ (версия из package.json) и __FRONTEND_COMMIT__ (VITE_FRONTEND_COMMIT / GITHUB_SHA / git rev-parse) внедряются на этапе компиляции.
  • Прокси разработки: и dev server (порт 5173), и preview (порт 4173) проксируют /api, /files, /mcp/ на VITE_DEV_PROXY_TARGET (или FRONTEND_BACKEND_URL, по умолчанию http://localhost:8080). Для /api включена пересылка WebSocket (терминал песочницы и др.), тайм-аут увеличен до 180s; /mcp/ — длительное соединение Streamable HTTP встроенного MCP Server, тайм-аут 1 час.
  • Псевдонимы: @ → frontend/src; также исправлено определение входного файла для @vue-office/pptx.
  • Часто используемые скрипты: npm run dev / npm run build / npm run preview (локальный запуск службы на артефактах production-сборки — среда проверки, наиболее близкая к опубликованному образу) / npm run type-check / npm run test (tsx --test).

Production-образ (Dockerfile + nginx) ​

frontend/Dockerfile:

  • Начиная с v0.8.2 — двухэтапная сборка: node:24-bookworm-slim, зафиксированный по digest, выполняет npm ci + npm run build с $BUILDPLATFORM, затем dist/ копируется в слой выполнения. При сборке больше не требуется установка Node / npm на хост-машине и не нужно заранее генерировать dist/ (scripts/build_frontend_dist.sh по-прежнему используется для упаковки Lite / настольного приложения);
  • Базовый образ слоя выполнения зафиксирован по digest как nginx:1.30.3-alpine (в комментарии явно запрещено возвращаться к плавающему тегу — более новый Alpine 3.24+ не запускается на старом ядре CentOS 7, что однажды привело к сбою v0.7.0);
  • nginx.conf помещается как шаблон в /etc/nginx/templates/default.conf.template; общие параметры прокси для /api/, /mcp/ и загрузки навыков находятся в nginx-api-proxy.conf (копируется как есть в /etc/nginx/api-proxy.conf), а фрагмент уровня http — в nginx-http.conf (формат логов api_no_query без строки запроса). Открывается порт 80, точка входа — docker-entrypoint.sh.

Параметры сборки образа:

ИмяТипЗначение по умолчаниюОписание
NPM_REGISTRYbuild-argпустоЗеркало реестра, используемое npm ci; пусто — используется реестр npm по умолчанию
NODE_MAX_OLD_SPACE_SIZEbuild-arg4096Верхний предел кучи Node на этапе сборки (MB), чтобы избежать OOM при сборке Vite
VITE_FRONTEND_COMMITbuild-argunknownCommit фронтенда, внедряемый в страницу; объявлен после npm ci, его изменение не инвалидирует кэш слоя зависимостей

frontend/docker-entrypoint.sh (внедрение конфигурации времени выполнения):

  1. Генерирует /usr/share/nginx/html/config.js, записывая MAX_FILE_SIZE_MB, MAX_SKILL_BUNDLE_SIZE_MB и DEFAULT_LOCALE в window.__RUNTIME_CONFIG__ для чтения фронтендом во время работы;
  2. Рендерит шаблоны nginx с помощью envsubst;
  3. Запускает nginx в foreground.
ИмяТипЗначение по умолчаниюОписание
MAX_FILE_SIZE_MBцелое (MB)50Верхний предел тела запроса для всего сайта и верхний предел размера загрузки во фронтенде
MAX_SKILL_BUNDLE_SIZE_MBцелое (MB)256Действует только на маршрут загрузки ZIP навыков; если меньше MAX_FILE_SIZE_MB, поднимается до этого значения, максимум 512
DEFAULT_LOCALEстрокапустоЯзык интерфейса по умолчанию; допускаются только zh-CN / en-US / ru-RU / ko-KR / ja-JP, остальные значения отбрасываются
APP_HOSTстрокаappИмя хоста бэкенда
APP_PORTцелое8080Порт бэкенда
APP_SCHEMEстрокаhttpПротокол бэкенда; для удалённого HTTPS-бэкенда можно задать https

Ключевое поведение frontend/nginx.conf:

  • SPA fallback: под / — try_files ... /index.html, а для index.html задан no-cache (чтобы после обновления пользователи не получили старую версию); для /assets/* с хешем задан неизменяемый кэш на год;
  • Прокси API: /api/ и /files проксируются на ${APP_SCHEME}://${APP_HOST}:${APP_PORT}; для /api/ в отношении SSE отключены proxy_buffering / кэширование / блочное кодирование, тайм-ауты чтения-записи увеличены до 3600s и настроены 3 повторные попытки upstream;
  • Встроенный MCP Server /mcp/: проксируется на бэкенд по исходному пути, параметры прокси те же, что у /api/; внешние MCP-клиенты могут подключаться к /mcp/<endpoint_id>, используя домен сайта напрямую;
  • Каналы WebSocket: для /api/v1/sessions/<id>/sandbox/(terminal|desktop) (терминал и графический рабочий стол песочницы) и /api/v1/local-browser/extension (подключение расширения браузера BrowserSkill) отдельно включён Upgrade, а из журнала доступа убрана строка запроса, чтобы не записывать тикет рукопожатия; внутренний кластерный путь /api/v1/local-browser/internal сразу возвращает 404;
  • Загрузка пакетов навыков: два коллекционных маршрута /api/v1/skills/catalog и /api/v1/sandbox-configs/<id>/skills отдельно используют MAX_SKILL_BUNDLE_SIZE, остальные эндпоинты загрузки по-прежнему ограничены MAX_FILE_SIZE;
  • Короткие ссылки на ресурсы /r/: location ^~ /r/ также проксируется на бэкенд. Канал IM переписывает изображения resource:// в <APP_EXTERNAL_URL>/r/<token>; без этой конфигурации запрос попадёт в SPA fallback, и на стороне IM изображение отобразится пустым (подробнее см. Интеграция с IM);
  • Страница встраивания: /embed/* возвращает embed.html (отдельный location, не наследует X-Frame-Options: SAMEORIGIN основного сайта). nginx сначала через внутренний подзапрос /_embed-frame-policy запрашивает у бэкенда GET /api/v1/embed-frame-policy разрешённые источники хоста для этого канала и добавляет возвращённый Content-Security-Policy в ответ; при отсутствии канала, его деактивации, отсутствии разрешённых источников хоста или недоступности бэкенда загрузка отклоняется. Пользовательский обратный прокси должен сохранить этот шаг, иначе белый список источников хоста не сработает. /weknora-widget.js — статический загрузчик для сторонних сайтов; в начале файла приведён дополнительный необязательный пример server-блока отдельного поддомена embed;
  • Включены gzip (в комментарии зафиксирована измеренная выгода: при низкой пропускной способности первый экран сокращается с 25s до 3-5s) и набор заголовков безопасности ответа (X-Frame-Options, X-Content-Type-Options, Referrer-Policy и др., повторно объявленных в каждом location, чтобы обойти проблему ненаследования add_header в nginx).

Связь с настольным приложением (Wails) ​

frontend/src/wailsjs/ — автоматически сгенерированный фреймворком Wails код привязок (в заголовке файлов указано "automatically generated. DO NOT EDIT"):

  • wailsjs/go/main/App.d.ts / App.js: JS-привязки методов структуры App со стороны Go, включая CheckForUpdates / AutoCheckForUpdates (проверка настольных обновлений), GetAPIBaseURL / GetAPILanBaseURL, настройки порта и внешнего прослушивания встроенной HTTP-службы настольного приложения (GetDesktopHTTPPortSetting, SetDesktopHTTPBindPublicSetting и др.), а также GetAutoSetupToken (возвращает случайные учётные данные, сгенерированные при запуске настольного процесса; по ним фронтенд вызывает auto-setup для входа без регистрации, см. раздел о навигационных хуках выше);
  • wailsjs/runtime/: API runtime Wails (управление окном и др.); при вызове фронтендом в браузерной среде происходит тихая деградация через try/catch (например, useTheme.ts).

Содержимым окна настольного приложения является именно этот код фронтенда; автоматический вход в настольном приложении, восстановление глубоких ссылок и перетаскиваемая область заголовка, помеченная --wails-draggable, — всё это адаптации для настольной формы.

Навигация настроек и возможности развёртывания ​

Точки входа настроек сгруппированы по задачам; в интеграциях публикации есть страницы подключения IM, веб-встраивания, API, MCP Server, CLI, расширения Chrome, Claw Skill и др.; конфигурация песочницы, личные переменные и память пространства / личная память имеют отдельные интерфейсы управления в центре настроек; навыки, службы MCP и подключение браузера — в инструментарии. Новые точки входа следует добавлять, переиспользуя существующую регистрацию в frontend/src/config/integrations.ts, frontend/src/config/toolbox.ts, frontend/src/config/settingsAccess.ts и т. д., одновременно проверяя группировку боковой панели.

GET /api/v1/system/capabilities возвращает edition и возможности supported/reason. Фронтенд скрывает или отключает точки входа в зависимости от фактических возможностей развёртывания (навигационные хуки, меню слева, разделы настроек, вкладки инструментария читают один и тот же снимок): при неудачном определении возможностей или отсутствии какого-либо ключа в старом бэкенде по умолчанию сохраняется видимость; organizations в версии Lite всегда скрыто; settings.sandbox.docker / settings.sandbox.host отображаются, только если бэкенд явно возвращает supported: true. Видимость во фронтенде лишь улучшает опыт работы, серверная маршрутизация продолжает проверять роли и возможности. Интерфейсы см. в Системный API.

Версия v0.8.3 · MIT License