Веб-фронтенд (frontend/)
Веб-фронтенд aihelpme.ru — это одностраничное приложение (SPA) на Vue 3 + TypeScript + Vite, предоставляющее весь интерфейс взаимодействия: управление базами знаний, диалоги с агентами, организационную работу, системные настройки и т. д. Один и тот же код обслуживает три формы:
- Стандартное веб-развёртывание: артефакт сборки Vite обслуживается контейнером nginx,
/apiпроксируется на бэкенд; - Веб-встраивание (Embed): отдельная облегчённая точка входа
frontend/embed.html+frontend/src/embed-main.ts, позволяющая сторонним сайтам встраивать диалог с агентом через iframe / всплывающее окно; - Настольная версия (Wails): через автоматически сгенерированные привязки в
frontend/src/wailsjs/общается с Go-стороной настольного процесса, поддерживает область перетаскивания--wails-draggable, синхронизацию светлой/тёмной темы окна и другие настольные функции.
Обзор технологического стека
Согласно frontend/package.json (версия 0.8.3):
| Категория | Выбор | Версия | Описание |
|---|---|---|---|
| Фреймворк | Vue | ^3.5.34 | Composition 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.0 | createWebHistory, см. frontend/src/router/index.ts |
| Мультиязычность | vue-i18n | ^11.4.2 | zh-CN / en-US / ru-RU / ko-KR / ja-JP |
| HTTP | axios | ^1.16.0 | Единый экземпляр инкапсулирован в frontend/src/utils/request.ts |
| SSE-поток | @microsoft/fetch-event-source | ^2.0.1 | Потоковые ответы в чате, см. frontend/src/api/chat/streame.ts |
| Рендеринг Markdown | marked / 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-scroller | 2.0.0-beta.8 | Виртуальная прокрутка списка сообщений |
| Стили | Less + CSS Variables | less ^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 |
/login | login | src/views/auth/Login.vue | Страница входа (с OIDC, переключением языка, анимированным фоном) |
/register | registerByInvite | src/views/auth/Login.vue | Страница регистрации по приглашению — переиспользует компонент Login, при монтировании проверяет ?token=xxx и переключается в режим регистрации по приглашению |
/onboarding/workspace | workspaceOnboarding | src/views/auth/WorkspaceOnboarding.vue | Страница онбординга рабочего пространства для пользователей без тенанта (создать или дождаться приглашения); требуется вход, но наличие тенанта не обязательно |
/join | joinOrganization | Перенаправление | Ссылка-приглашение для вступления в организацию: преобразует ?code= в параметр invite_code и переходит на /platform/organizations |
/knowledgeBase | home | src/views/knowledge/KnowledgeBase.vue | Детали базы знаний (устаревший путь верхнего уровня) |
/platform | Platform | src/views/platform/index.vue | Основной макет платформы (меню слева + выход маршрутизации + модальное окно глобальных настроек + оверлей drag-and-drop загрузки); по умолчанию перенаправляет на список баз знаний |
/platform/dev/markdown | markdownTest | src/views/dev/MarkdownTestPage.vue | Страница визуального регрессионного теста рендеринга Markdown, регистрируется только в режиме разработки (import.meta.env.DEV) |
Дочерние маршруты /platform
| Путь | Имя | Компонент | Функция |
|---|---|---|---|
/platform/knowledge-bases | knowledgeBaseList | src/views/knowledge/KnowledgeBaseList.vue | Список баз знаний: боковая панель пространства (все / мои / по организации / избранное / недавние), список карточек, точка входа создания; поддерживает сортировку по времени обновления / создания / имени (components/ResourceSortControl.vue, применимо и к списку агентов) |
/platform/knowledge-bases/:kbId | knowledgeBaseDetail | src/views/knowledge/KnowledgeBase.vue | Детали базы знаний: список документов (сортировка по времени обновления / создания / имени файла, сортировка выполняется на сервере, по умолчанию по времени создания по убыванию), загрузка, статус разбора, точка входа сессии, Wiki и т. д. |
/platform/agents | agentList | src/views/agent/AgentList.vue | Список и управление агентами, редактирование через AgentEditorModal.vue; требуется возможность развёртывания agents |
/platform/toolbox/:section? | toolbox | src/views/toolbox/Toolbox.vue | Инструментарий: три вкладки skills (навыки), mcp (службы MCP), browserconnection (подключение браузера), см. раздел «Инструментарий» ниже |
/platform/artifacts | artifactLibrary | src/views/artifacts/ArtifactLibrary.vue | Библиотека артефактов: сводит файлы, созданные агентами в разных сессиях; требуется возможность развёртывания settings.sandbox |
/platform/creatChat | globalCreatChat | src/views/creatChat/creatChat.vue | Страница создания диалога: рекомендуемые вопросы, запуск сессии после выбора баз знаний / агента / модели |
/platform/knowledge-bases/:kbId/creatChat | kbCreatChat | src/views/creatChat/creatChat.vue | Запуск нового диалога из контекста конкретной базы знаний (тот же компонент) |
/platform/chat/:chatid | chat | src/views/chat/index.vue | Страница сессии: поток сообщений (потоковый рендеринг SSE, скелетон, виртуальная прокрутка), панель ссылок, предпросмотр вложений |
/platform/organizations | organizationList | src/views/organization/OrganizationList.vue | Список организаций: создание/вступление в организацию, управление участниками и общими ресурсами (вместе с OrganizationSettingsModal.vue); требуется возможность развёртывания organizations, в версии Lite всегда скрыто. При добавлении участника поиск идёт точно по полному ID пространства, а не нечёткий поиск по имени пространства |
/platform/settings | settings | src/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/admins | systemSettings / systemAdmins | Перенаправление | Старые пути системного администрирования → /platform/settings?section=system-global, требуется requiresSystemAdmin (представления в src/views/system/: SystemSettings.vue, SystemAuditLog.vue, PlatformAPIKeys.vue и др.) |
/platform/system/queues | systemQueues | Перенаправление | → /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, faq | faq — только для баз типа 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):
- Пропуск обратного вызова OIDC: если hash URL содержит
oidc_result=/oidc_error=, пропуск выполняется напрямую, а обработка передаётсяApp.vue; - Старые закладки инструментария:
/platform/settings?section=skills|mcp|browserconnectionперенаправляются на/platform/toolbox/<section>; - Восстановление глубоких ссылок Lite / настольного приложения: при жёстком обновлении в режиме Lite, попадающем на домашнюю страницу по умолчанию, из
sessionStorageвосстанавливается последний посещённый подпуть/platform(кроме страницы организации); - Восстановление сессии: если пользователь не вошёл, сначала через
weknora_tokenизlocalStorageвызываетсяgetCurrentUser()для восстановления сессии (одновременно обновляются memberships, чтобы избежать задержки изменений ролей); - Автоматический вход в настольном приложении: при неудачном восстановлении однократно выполняется
autoSetup(). Начиная с v0.8.2 он действует только в нативном настольном приложении: сначала через привязку WailsGetAutoSetupToken()получаются случайные учётные данные текущего процесса, затем с заголовкомX-WeKnora-Desktop-TokenвызываетсяPOST /api/v1/auth/auto-setup; в версии Lite, открытой в браузере, такой привязки нет, поэтому используется обычная регистрация / вход. При неудаче вlocalStorageставится метка, чтобы избежать повторных попыток; - Порог тенанта: пользователь вошёл, но нет действующего тенанта → переход на
/onboarding/workspace; - Порог возможностей развёртывания: если
meta.requiredCapabilityмаршрута (например,agents,organizations,settings.sandbox) не поддерживается текущим развёртыванием, после уведомления выполняется возврат к списку баз знаний; при неудачном определении возможностей пропуск, а окончательную проверку выполняет интерфейс бэкенда; - Порог SystemAdmin: маршруты с
requiresSystemAdminдля не-системных администраторов перенаправляют обратно к списку баз знаний (блокировка только на уровне UI, на сервере есть отдельная строгая проверка).
Управление состоянием (Pinia)
Store и вспомогательные модули в frontend/src/stores/:
| Файл | Store ID / тип | Назначение |
|---|---|---|
stores/auth.ts | useAuthStore | Ядро аутентификации: user / token / refreshToken / tenant / memberships / определение роли (hasRole, isSystemAdmin), флаг режима Lite; при выходе каскадно очищает кэш уровня пространства других store и перезагружает предпочтения пользователя (тема/шрифт) |
stores/chatResources.ts | useChatResourcesStore | Кэш ресурсов уровня пространства (TTL 60s): списки баз знаний, агентов, моделей, провайдеров веб-поиска, переиспользуется селекторами чата/создания диалога |
stores/editorResources.ts | useEditorResourcesStore | Кэш ресурсов редактора/настроек (TTL 60s): конфигурация и статус движков хранилища, шаблоны промптов, движки разбора, системная информация, службы MCP, навыки, пресеты типов агентов, конфигурация поиска |
stores/commandPalette.ts | useCommandPaletteStore | Переключатель и запросы глобальной командной палитры (⌘K / Ctrl+K); недавние поиски хранятся в области (user, tenant), чтобы избежать утечки между аккаунтами |
stores/organization.ts | useOrganizationStore | Организационная работа: список организаций, участники, общие базы знаний/агенты, заявки на вступление и их проверка, повышение роли — полный набор действий |
stores/organizationState.ts | Модуль чистых функций | Чистая логика upsert / merge списка организаций, влияние проверки вступления на число участников и др. (с юнит-тестом organizationState.test.ts) |
stores/settings.ts | Store настроек | Конфигурация сессии и агента: выбранные базы знаний/файлы/теги/MCP/навыки/инструменты, конфигурация моделей, конфигурация Ollama, переключатель веб-поиска и т. д. |
stores/settingsStorage.ts | Модуль чистых функций | Чтение, клонирование и исправление встроенных режимов агента при сохранении настроек (ключ WeKnora_settings) (с settingsStorage.test.mjs) |
stores/menu.ts | useMenuStore | Структура меню навигации слева (пункты создания диалога, баз знаний, агентов и др.) и заголовки i18n |
stores/knowledge.ts | knowledgeStore | Список карточек знаний и их общее число (облегчённый) |
stores/ui.ts | useUIStore | Глобальное состояние UI: модальное окно настроек, модальное окно редактирования базы знаний, редактор ручных документов, сворачивание боковой панели — переключатели и параметры |
stores/uploadConfirm.ts | Store подтверждения загрузки | Состояние диалога подтверждения параметров обработки перед загрузкой / импортом по URL / ручным вводом / повторным разбором |
stores/versionedRequest.ts | Модуль чистых функций | createVersionedRequestCoordinator: координатор кэшированных запросов с версией, предотвращающий перезапись новых данных старыми ответами (с versionedRequest.test.ts) |
stores/deploymentCapabilities.ts | useDeploymentCapabilitiesStore | Снимок возможностей развёртывания (GET /api/v1/system/capabilities), используется навигационными хуками, боковой панелью, настройками и инструментарием для определения видимости точек входа |
stores/modelProviders.ts | useModelProvidersStore | Кэш каталога поставщиков моделей (GET /api/v1/models/providers, загружается по типу модели); редактор моделей и карточки моделей единообразно читают информацию о поставщике отсюда |
stores/uploadTasks.ts (+ uploadQueue.ts / uploadTasksCore.ts / uploadTasksState.ts) | useUploadTasksStore | Очередь загрузки файлов знаний: ограничение параллельной передачи, отмена / повтор, опрос прогресса разбора, управление плавающей панелью прогресса загрузки; загрузка продолжается после ухода со страницы базы знаний |
stores/browserConnection.ts | useBrowserConnectionStore | Состояние подключения локального браузера, используется вкладками инструментария и статусом боковой панели |
stores/sessionActivity.ts | useSessionActivityStore | Состояние «в процессе» для сессий в боковой панели |
Обёртка API (frontend/src/api/)
Основа запросов
- Экземпляр axios:
frontend/src/utils/request.tsсоздаёт единый экземпляр (baseURLберётся изgetApiBaseUrl()вfrontend/src/utils/api-base.ts, учитывает ViteBASE_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_REGISTRY | build-arg | пусто | Зеркало реестра, используемое npm ci; пусто — используется реестр npm по умолчанию |
NODE_MAX_OLD_SPACE_SIZE | build-arg | 4096 | Верхний предел кучи Node на этапе сборки (MB), чтобы избежать OOM при сборке Vite |
VITE_FRONTEND_COMMIT | build-arg | unknown | Commit фронтенда, внедряемый в страницу; объявлен после npm ci, его изменение не инвалидирует кэш слоя зависимостей |
frontend/docker-entrypoint.sh (внедрение конфигурации времени выполнения):
- Генерирует
/usr/share/nginx/html/config.js, записываяMAX_FILE_SIZE_MB,MAX_SKILL_BUNDLE_SIZE_MBиDEFAULT_LOCALEвwindow.__RUNTIME_CONFIG__для чтения фронтендом во время работы; - Рендерит шаблоны nginx с помощью
envsubst; - Запускает 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.
