Справочник API: FAQ и Wiki
Управление записями FAQ и страницами Wiki в базе знаний: импорт, поиск, редактирование и восстановление версий.
Обе группы — подресурсы содержимого KB: чтение — Viewer+ и KB read (API key retrieve/full); запись — «создатель KB OR Admin+» и KB write (API key ingest/full); обе ограничены белым списком KB. Межбазовый поиск по Wiki POST /wiki-search не содержит KB в пути: Viewer+ и API key retrieve/full; внутри handler проверяются allow-list каждой целевой базы и права Viewer на общие базы.
FAQ (/api/v1/knowledge-bases/:id/faq)
GET /api/v1/knowledge-bases/:id/faq/entries
Назначение: список записей FAQ.
| Параметр запроса | Тип | Обязательный | Описание |
|---|---|---|---|
page / page_size | int | Нет | Пагинация |
tag_id | int | Нет | seq_id одиночного тега (устаревшее) |
tag_ids | string | Нет | UUID тегов через запятую |
keyword | string | Нет | Ключевое слово |
search_field | string | Нет | standard_question/similar_questions/answers (по умолчанию все поля) |
sort_order | string | Нет | asc (по умолчанию по времени обновления в порядке убывания) |
is_enabled | bool | Нет | Фильтр по состоянию включения: true — только включённые, false — только отключённые, без параметра возвращаются все; другие значения — 400 |
Ответ: 200 {"success":true,"data":{список FAQEntry с пагинацией}}
curl "$BASE/api/v1/knowledge-bases/kb-1/faq/entries?page=1&is_enabled=false" -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledge-bases/:id/faq/entries/export
Назначение: экспорт FAQ. Параметры запроса: format (csv по умолчанию / json).
Ответ: 200 загрузка файла (text/csv или application/json).
curl -OJ "$BASE/api/v1/knowledge-bases/kb-1/faq/entries/export?format=csv" -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledge-bases/:id/faq/entries/:entry_id
Назначение: детали записи FAQ (entry_id — целочисленный seq_id).
Ответ: 200 {"success":true,"data":{FAQEntry}}
curl $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12 -H "Authorization: Bearer $TOKEN"POST /api/v1/knowledge-bases/:id/faq/entries
Назначение: массовый upsert / импорт (асинхронная задача). Метод Handler UpsertEntries.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
entries | []FAQEntryPayload | Да (binding:"required") | Массив записей |
mode | string | Да (binding:"oneof=append replace") | Добавление или замена |
knowledge_id | string | Нет | ID сущности знания FAQ |
task_id | string | Нет | Пользовательский ID задачи; допускаются только буквы, цифры, _, -; максимум 128 символов, иначе 400 |
dry_run | bool | Нет | Только проверка без записи в базу |
Ответ: 200 {"success":true,"data":{"task_id"}}
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entries -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"mode":"append","entries":[{"standard_question":"Как вернуть деньги?","answers":["Свяжитесь со службой поддержки"]}]}'POST /api/v1/knowledge-bases/:id/faq/entry
Назначение: создать одну запись FAQ. Тело запроса (types.FAQEntryPayload):
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
standard_question | string | Да (binding:"required") | Стандартный вопрос |
similar_questions | []string | Нет | Похожие вопросы |
negative_questions | []string | Нет | Негативные примеры вопросов |
answers | []string | Нет | Список ответов |
answer_strategy | string | Нет | all / random |
tag_id | int64 | Нет | seq_id тега |
tag_name | string | Нет | Имя тега |
is_enabled / is_recommended | *bool | Нет | Включение/рекомендация |
Ответ: 200 {"success":true,"data":{FAQEntry}}
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entry -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"standard_question":"Как вернуть деньги?","answers":["Возврат возможен в течение 7 дней"]}'PUT /api/v1/knowledge-bases/:id/faq/entries/:entry_id
Назначение: обновить одну запись FAQ (тело запроса как при создании).
Ответ: 200 {"success":true,"data":{FAQEntry}}
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"standard_question":"Как вернуть деньги?","answers":["Возврат возможен в течение 30 дней"]}'POST /api/v1/knowledge-bases/:id/faq/entries/:entry_id/similar-questions
Назначение: добавить похожие вопросы. Тело запроса: {"similar_questions":["..."]} (binding:"required,min=1").
Ответ: 200 {"success":true,"data":{FAQEntry}}
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/entries/12/similar-questions \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"similar_questions":["Как оформить возврат"]}'PUT /api/v1/knowledge-bases/:id/faq/entries/fields
Назначение: массовое обновление полей записей (is_enabled/is_recommended/tag_id).
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
by_id | map[int64]object | Нет | Обновление по seq_id записи |
by_tag | map[int64]object | Нет | Массовое обновление по тегу |
exclude_ids | []int64 | Нет | Записи, исключаемые при by_tag |
Ответ: 200 {"success":true}
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/fields -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"by_id":{"12":{"is_enabled":false}}}'PUT /api/v1/knowledge-bases/:id/faq/entries/tags
Назначение: массово изменить теги записей. Тело запроса: {"updates":{"<entry_id>":<tag_id|null>}} (binding:"required,min=1"; null удаляет тег).
Ответ: 200 {"success":true}
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/entries/tags -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"updates":{"12":3}}'DELETE /api/v1/knowledge-bases/:id/faq/entries
Назначение: массово удалить записи. Тело запроса: {"ids":[int64]} (binding:"required,min=1").
Ответ: 200 {"success":true}
curl -X DELETE $BASE/api/v1/knowledge-bases/kb-1/faq/entries -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"ids":[12,13]}'POST /api/v1/knowledge-bases/:id/faq/search
Назначение: поиск по FAQ (семантика только для чтения; scoped key с retrieve тоже может вызывать).
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
query_text | string | Да (binding:"required") | Запрос |
vector_threshold | float64 | Нет | Порог вектора, по умолчанию 0.7 |
match_count | int | Нет | По умолчанию 10, максимум 50 |
first_priority_tag_ids / second_priority_tag_ids | []int64 | Нет | Фильтр по приоритету тегов |
only_recommended | bool | Нет | Только рекомендуемые записи |
Ответ: 200 {"success":true,"data":[FAQEntry (с match_type/score)]}
curl -X POST $BASE/api/v1/knowledge-bases/kb-1/faq/search -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' -d '{"query_text":"возврат"}'PUT /api/v1/knowledge-bases/:id/faq/import/last-result/display
Назначение: задать состояние отображения панели последнего результата импорта. Тело запроса: {"display_status":"open|close"} (binding:"required,oneof=open close").
Ответ: 200 {"success":true}
curl -X PUT $BASE/api/v1/knowledge-bases/kb-1/faq/import/last-result/display \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"display_status":"close"}'GET /api/v1/faq/import/progress/:task_id
Назначение: узнать прогресс импорта/dry-run FAQ (задачи изолированы по пространствам). Права: Viewer+; API key retrieve/ingest/full.
Ответ: 200 {"success":true,"data":{status,progress,failed_entries,...}}
curl $BASE/api/v1/faq/import/progress/task-1 -H "X-API-Key: $API_KEY"Wiki (/api/v1/knowledgebase/:kb_id/wiki)
Обратите внимание: префикс этой группы — /knowledgebase/:kb_id/wiki (в единственном числе, без дефиса). Handler: internal/handler/wiki_page.go. Ответы этой группы в основном сырые объекты (без обёртки success).
GET /api/v1/knowledgebase/:kb_id/wiki/pages
Назначение: список страниц Wiki.
| Параметр запроса | Тип | Обязательный | Описание |
|---|---|---|---|
page_type | string | Нет | Типы через запятую |
status | string | Нет | Состояние страницы |
query | string | Нет | Полнотекстовый поиск |
category_path | string | Нет | Фильтр по пути с разделителем / |
folder_id | string | Нет | Точный фильтр по папке (пустая строка = корень) |
category_depth | int | Нет | Глубина папки |
page / page_size | int | Нет | Пагинация (по умолчанию 1/20) |
sort_by / sort_order | string | Нет | Поле сортировки: title, created_at, updated_at, page_type, wiki_path, sort_order, depth; другие значения — по updated_at; по умолчанию updated_at desc |
Ответ: 200 WikiPageListResponse
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/pages?page=1" -H "Authorization: Bearer $TOKEN"POST /api/v1/knowledgebase/:kb_id/wiki/pages
Назначение: создать страницу. Тело запроса (types.WikiPage): slug, title, content, folder_id, page_type и т. д. (все необязательны; при отсутствии slug генерируется автоматически).
Ответ: 201 WikiPage
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/pages -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"title":"Обзор архитектуры","content":"# Обзор"}'PUT /api/v1/knowledgebase/:kb_id/wiki/move-page
Назначение: переместить страницу в папку. Тело запроса: {"slug":"<slug страницы>","folder_id":"<ID папки|пусто=корень>"} (slug обязателен).
Ответ: 200 WikiPage
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/move-page -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"slug":"overview","folder_id":"f-1"}'GET /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
Назначение: получить страницу (*slug — путь с подстановкой).
Ответ: 200 WikiPageDetail. Содержит все поля WikiPage и дополнительно in_link_titles, отображающие заголовки страниц, slug которых перечислен в in_links (например, {"concept/example":"Пример заголовка"}). Если разрешить обратные ссылки не удаётся, возвращается пустой объект; отсутствующие цели не попадают в сопоставление. При ошибке запроса заголовков возвращается 500, чтобы не отдавать неполный успешный ответ.
curl $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN"PUT /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
Назначение: обновить страницу (тело запроса как при создании). Старая версия сначала целиком сохраняется в wiki_page_revisions, version увеличивается, last_edit_source записывается как user (при записи инструментом Agent — agent).
Ответ: 200 WikiPage
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"content":"# Обновлённый обзор"}'GET /api/v1/knowledgebase/:kb_id/wiki/revisions/*slug
Назначение: история версий страницы (migration 000075). Права: Viewer+ + KBAccessRead.
| Параметр запроса | Тип | Обязательный | Описание |
|---|---|---|---|
version | int | Нет | Если передан — возвращает полный текст этой версии (для diff); недопустимое значение или < 1 — 400; не найдено — 404 (у версий, записанных до обновления, или у снимков, очищенных политикой хранения, полного текста нет — это нормально) |
limit | int | Нет | По умолчанию 50, максимум 200; действует только в режиме списка |
offset | int | Нет | Смещение пагинации |
Без version возвращается список истории (номера версий в порядке убывания, без основного текста) плюс текущий номер версии страницы; каждая запись содержит edit_source (pipeline / agent / user / revert), editor_id, edited_at.
Хранение истории имеет два предела: мягкий предел в 50 версий отсекает только снимки pipeline и с пустым источником, жёсткий предел в 200 версий действует для всех источников, поэтому ручные правки не вытесняются конвейером.
# Список истории
curl $BASE/api/v1/knowledgebase/kb-1/wiki/revisions/entity/acme-corp -H "Authorization: Bearer $TOKEN"
# Получить полный текст 3-й версии
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/revisions/entity/acme-corp?version=3" -H "Authorization: Bearer $TOKEN"POST /api/v1/knowledgebase/:kb_id/wiki/revert
Назначение: откатить страницу к исторической версии. Права: KB owner или Admin+ + KBAccessWrite.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
slug | string | Да | Целевая страница |
version | int | Да | Номер целевой версии (≥ 1) |
Откат не уменьшает номер версии: содержимое целевой версии записывается как новая версия, last_edit_source записывается как revert, поэтому откат тоже можно откатить. Откат к текущей версии возвращает 400 (обычно из-за устаревшего списка истории на фронтенде).
Ответ: 200 WikiPage
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/revert -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"slug":"entity/acme-corp","version":3}'DELETE /api/v1/knowledgebase/:kb_id/wiki/pages/*slug
Назначение: удалить страницу.
Ответ: 204 No Content
curl -X DELETE $BASE/api/v1/knowledgebase/kb-1/wiki/pages/overview -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/folders
Назначение: список папок. Параметры запроса: parent_id (пусто = корень), page_types (через запятую).
Ответ: 200 WikiFolderListResponse
curl $BASE/api/v1/knowledgebase/kb-1/wiki/folders -H "Authorization: Bearer $TOKEN"POST /api/v1/knowledgebase/:kb_id/wiki/folders
Назначение: создать папку.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
name | string | Да | Имя папки |
parent_id | string | Нет | Родительская папка |
Ответ: 201 WikiFolder
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/folders -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"Проектная документация"}'PUT /api/v1/knowledgebase/:kb_id/wiki/folders/:folder_id
Назначение: переименовать/переместить папку. Тело запроса: name, parent_id, move_parent (bool), все необязательны.
Ответ: 200 WikiFolder
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/folders/f-1 -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"name":"Проектирование архитектуры"}'DELETE /api/v1/knowledgebase/:kb_id/wiki/folders/:folder_id
Назначение: удалить папку.
Ответ: 204 No Content
curl -X DELETE $BASE/api/v1/knowledgebase/kb-1/wiki/folders/f-1 -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/index
Назначение: индексная страница Wiki (окна, сгруппированные по типу). Параметры запроса: types (через запятую), limit (1–200, по умолчанию 50), cursor (курсор).
Ответ: 200 WikiIndexResponse
curl $BASE/api/v1/knowledgebase/kb-1/wiki/index -H "Authorization: Bearer $TOKEN"Удалено
GET /api/v1/knowledgebase/:kb_id/wiki/log (журнал изменений Wiki) был снят вместе с migration 000077_remove_wiki_log, таблица wiki_log_entries удалена. Теперь изменения Wiki единообразно проецируются в поток активности базы знаний — используйте GET /api/v1/knowledge-bases/:id/activity.
GET /api/v1/knowledgebase/:kb_id/wiki/graph
Назначение: граф связей страниц.
| Параметр запроса | Тип | Обязательный | Описание |
|---|---|---|---|
mode | string | Нет | overview (по умолчанию) / ego |
center | string | Нет | slug центра в режиме ego (обязателен для ego) |
depth | int | Нет | 1–3, по умолчанию 1 |
types | string | Нет | Фильтр по page_type |
limit | int | Нет | По умолчанию 500, максимум 2000 |
Ответ: 200 WikiGraphData
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/graph?mode=overview" -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/stats
Назначение: статистика Wiki.
Ответ: 200 WikiStats
curl $BASE/api/v1/knowledgebase/kb-1/wiki/stats -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/search
Назначение: поиск страниц. Параметры запроса: q (обязателен), limit (по умолчанию 10).
Семантика сопоставления зависит от диалекта хранилища:
- Postgres:
qсопоставляется как POSIX-регулярное выражение (~*, без учёта регистра). - SQLite / Lite: сопоставление как буквальная подстрока
LIKE;%/_экранируются и не считаются подстановочными знаками.
Ответ: 200 {"pages":[WikiPage]}
curl "$BASE/api/v1/knowledgebase/kb-1/wiki/search?q=развёртывание" -H "Authorization: Bearer $TOKEN"POST /api/v1/wiki-search
Назначение: поиск по страницам Wiki через несколько баз знаний (без сессии, не гибридный поиск). Handler: SearchPagesAcross в internal/handler/wiki_page.go. Алгоритм тот же, что и для одиночной базы GET .../wiki/search (заголовок > slug > summary > основной текст); после одного запроса к нескольким базам выполняется глобальное усечение по match_rank. API key: retrieve/full.
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
query | string | Да (binding:"required") | То же, что q для одиночной базы: в Postgres — POSIX-регулярное выражение (без учёта регистра); в SQLite / Lite — буквальная подстрока LIKE |
knowledge_base_ids | []string | Условно обязательный | Несколько баз; нужно указать хотя бы одно из knowledge_base_ids/knowledge_base_id, максимум 32 |
knowledge_base_id | string | Нет | Поле для совместимости с одиночной базой; объединяется в ids |
limit | int | Нет | Глобальный top-N, по умолчанию 10, максимум 50 |
Если в любой из целевых баз не включён wiki → 400. База не существует или нет права на чтение → 404. Выход за белый список API Key → 403. Недопустимое регулярное выражение (Postgres) → 400.
Ответ: 200 {"success":true,"data":[WikiSearchHit]}. Совпадение содержит только навигационные поля + match_snippet, без основного текста; полный текст — через GET /knowledgebase/:kb_id/wiki/pages/{slug}.
| Поле ответа | Тип | Описание |
|---|---|---|
id | string | ID страницы |
knowledge_base_id | string | База-источник; при межбазовом поиске используется для сборки URL чтения страницы |
slug | string | slug страницы |
title | string | Заголовок |
page_type | string | Тип страницы |
aliases | []string | Псевдонимы |
summary | string | Сводка |
match_snippet | string | Примерно 60 символов вокруг первого совпадения в тексте: 60+совпадение+60; при отсутствии совпадения в тексте опускается. snippet по-прежнему компилирует query как регулярное выражение Go; в SQLite, если query содержит метасимволы регулярных выражений, совпадение в базе возможно, а snippet может быть пустым |
content, дерево/ссылки/метаданные и временные метки в результаты поиска не входят. Поиск по одиночной базе GET .../wiki/search по-прежнему возвращает полный WikiPage.
curl -X POST $BASE/api/v1/wiki-search -H "X-API-Key: $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"query":"развёртывание|релиз","knowledge_base_ids":["kb-1","kb-2"],"limit":10}'POST /api/v1/knowledgebase/:kb_id/wiki/rebuild-links
Назначение: перестроить взаимные ссылки страниц. Права на запись. Без тела запроса.
Ответ: 200 {"message":"Links rebuilt successfully"}
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/rebuild-links -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/lint
Назначение: отчёт о проверке согласованности Wiki.
Ответ: 200 WikiLintReport
curl $BASE/api/v1/knowledgebase/kb-1/wiki/lint -H "Authorization: Bearer $TOKEN"POST /api/v1/knowledgebase/:kb_id/wiki/auto-fix
Назначение: автоматически исправить проблемы lint. Права на запись. Без тела запроса.
Ответ: 200 {"fixed":N,"message":"Auto-fixed N issues"}
curl -X POST $BASE/api/v1/knowledgebase/kb-1/wiki/auto-fix -H "Authorization: Bearer $TOKEN"GET /api/v1/knowledgebase/:kb_id/wiki/issues
Назначение: список проблем. Параметры запроса: slug (фильтр по странице), status (pending/ignored/resolved).
Ответ: 200 [WikiPageIssue]
curl $BASE/api/v1/knowledgebase/kb-1/wiki/issues -H "Authorization: Bearer $TOKEN"PUT /api/v1/knowledgebase/:kb_id/wiki/issues/:issue_id/status
Назначение: обновить состояние проблемы. Права на запись. Тело запроса: {"status":"pending|ignored|resolved"} (binding:"required"). issue_id должен принадлежать базе знаний из пути, иначе 404.
Ответ: 200 {"message":"Issue status updated successfully"}
curl -X PUT $BASE/api/v1/knowledgebase/kb-1/wiki/issues/i-1/status -H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' -d '{"status":"resolved"}'Справочник по реализации
Регистрация маршрутов: RegisterFAQRoutes и RegisterWikiPageRoutes в internal/router/routes_knowledge.go. Handler: internal/handler/faq.go, internal/handler/wiki_page.go.
