База данных и миграции
Система использует версионированные миграции для поддержки структуры базы данных, при этом для PostgreSQL и SQLite используются отдельные каталоги миграций. Миграции могут выполняться автоматически при запуске приложения или вручную с помощью скриптов; при добавлении новых полей или таблиц необходимо поддерживать обе ветки.
Поддерживаемые базы данных
Основное приложение подключается к базе данных через GORM, драйвер определяется переменной окружения DB_DRIVER. Оператор switch в функции initDatabase() в файле internal/container/container.go принимает только два значения:
DB_DRIVER | Описание |
|---|---|
postgres | Стандартный режим. Поддерживает как нативный PostgreSQL (+pgvector), так и ParadeDB (ветка PostgreSQL со встроенными pg_search/BM25, официальный образ compose по умолчанию paradedb/paradedb:v0.25.11-pg17). DSN GORM формируется из DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME, принудительно устанавливаются sslmode=disable и TimeZone=UTC |
sqlite | Lite-режим. Путь берется из DB_PATH (по умолчанию ./data/weknora.db), в DSN добавляются параметры _journal_mode=WAL&_busy_timeout=5000&_foreign_keys=on, также загружается расширение sqlite-vec (sqlite_vec.Auto()) для векторного поиска |
| Другие значения | Выдает ошибку unsupported database driver |
MySQL не является основным вариантом базы данных: драйвер go-sql-driver/mysql в go.mod используется для регистрации драйвера индексации Doris (протокол MySQL, database/sql, см. комментарии в импортах container.go). Файл migrations/mysql/00-init-db.sql является одноразовым скриптом инициализации для 10 ключевых таблиц (tenants/models/knowledge_bases/knowledges/sessions/messages/message_suggestion_sets/message_suggestion_events/chunks/chunk_revisions), на который не ссылается никакой код Go или скрипты. Он не включен в процесс запуска приложения и может рассматриваться как устаревший или предназначенный для внешней инициализации.
Механизм индексации (хранение векторных индексов/ключевых слов) отделен от основной базы данных и управляется через RETRIEVE_DRIVER (postgres / elasticsearch / qdrant / milvus / sqlite и др., подробности см. в «Руководстве по точкам расширения»). Если RETRIEVE_DRIVER не содержит postgres, в DSN миграции добавляется options=-c app.skip_embedding=true, что позволяет пропустить миграции для таблицы embeddings с помощью этого условия GUC.
Структура каталогов миграций
migrations/
├── versioned/ # Версионированные миграции для PostgreSQL/ParadeDB: версии с 000000 по 000118 (всего 119 версий, 238 файлов .up/.down.sql)
├── sqlite/ # Миграции для SQLite: 000000_init (полная схема) + версии 000001-000036
├── paradedb/ # Дополнительные скрипты для ParadeDB: 00-init-db.sql, 01-migrate-to-paradedb.sql (переход существующей базы)
└── mysql/ # 00-init-db.sql, устаревший скрипт инициализации MySQL (не используется в коде)- Каталог
versioned/для PostgreSQL содержит миграции от000000_initдо000118_mcp_oauth_timestamp_tz; - В
sqlite/версия000000_initиспользуется как полная инициализация (учтены диалектные различия: JSONB→TEXT, SERIAL→AUTOINCREMENT и т.д.), за ней следуют инкрементальные версии (на текущий момент до000036_messages_attachment_lookup), которые также последовательно выполняются через golang-migrate; - Расширения
uuid-ossp,vector,pg_trgm,pg_searchи другие создаются при выполнении миграцийversioned/(000000, 000002); BM25-индекс использует китайский токенизатор Lindera и создается для поляembeddings.content; - Скрипт
paradedb/00-init-db.sqlсодержит как создание расширений, так и операторы создания таблиц для старых версий. Он не вызывается через compose или код. Не используйте его в качестве скрипта initdb для базы данных: создание старых таблиц приведет к ошибке при выполнении000000_init.
Обзор истории миграций versioned/ (по темам)
| Диапазон версий | Тема | Ключевые таблицы/поля |
|---|---|---|
| 000000 | Инициализация ядра | tenants, models, knowledge_bases, knowledges, chunks, sessions, messages |
| 000001 | Аутентификация + Agent + MCP | users, auth_tokens, custom_agents, mcp_services, knowledge_tags |
| 000002-000011 | Векторы/Поиск | embeddings (HNSW + BM25, под управлением app.skip_embedding), chunks.flags, seq_id, индекс ParadeDB BM25 |
| 000012-000018 | Сотрудничество между тенантами | organizations, organization_members, kb_shares, agent_shares, organization_join_requests |
| 000019-000028 | Сообщения/IM | Расширение messages (images, rendered_content, agent_duration_ms), im_channels, im_channel_sessions |
| 000029-000036 | Абстракция источников данных и векторных хранилищ | data_sources, sync_logs, web_search_providers, vector_stores, конфигурация asr_config/vector_store_id в базе знаний |
| 000037-000041 | Wiki и очереди задач | wiki_pages, wiki_folders, wiki_page_issues, wiki_log_entries (удалено в 000077), task_pending_ops, task_dead_letters |
| 000042-000054 | RBAC / Аудит / Приглашения / Настройки системы | mcp_tool_approvals, tenant_members, audit_logs, organization_tenant_members (переименовано из organization_members), user_resource_favorites, tenant_invitations, user_kb_pins, system_settings и users.is_system_admin (000053), поля ссылок приглашений tenant_invitations.token/accepted_count (000054) |
| 000055-000060 | Конвейер обработки и каналы эмбеддинга | knowledge_processing_spans, knowledges.pending_subtasks_count (000056, статус finalizing), embed_channels, индекс HNSW 1024 измерений |
| 000061-000067 | Иерархия Wiki / OAuth / Мультитеги документов / Идентификаторы принципалов / Предложения вопросов | Иерархия wiki_pages, mcp_oauth_clients, mcp_oauth_tokens, knowledge_tag_relations, поля идентификаторов (000064: tenants.api_principal_config, mcp_oauth_tokens.principal_type/principal_id), tenant_api_keys (000065, удаление tenants.api_key), message_suggestion_sets, message_suggestion_events |
| 000068-000074 | Хранилища/Ресурсы/Временные документы | storage_backends, resources, resource_bindings, resource_access_grants, temporary_documents, API key на уровне платформы, продление срока действия OAuth |
| 000075-000076 | История версий Wiki и индексация | wiki_page_revisions, wiki_pages.last_edit_source/last_editor_id, префиксный индекс knowledges.metadata->>'external_id' |
| 000077 | Удаление логов операций Wiki | Удаление wiki_log_entries и исторических страниц page_type = 'log'; изменения Wiki записываются в ленту активности базы знаний |
| 000078 | Редактирование блоков и пользовательские метаданные | Добавление в chunks полей source_content/content_revision/index_status/last_editor_id/context_header, новая таблица chunk_revisions, поле custom_metadata в knowledges |
| 000079 | Дерево папок базы знаний | Добавление folder_path в knowledges с обратной миграцией путей (ранее путь был в file_name), индекс (tenant_id, knowledge_base_id, folder_path) |
Миграции после 000080
| Версия | Изменение |
|---|---|
| 000080 | knowledge_bases.auto_tag_config |
| 000081 | messages.artifacts, сохранение сгенерированных файлов (с 000103 перенесено в message_artifacts) |
| 000082 | tenant_sandbox_configs, управление несколькими бэкендами и сроками смены конфигурации |
| 000083 | sessions.sandbox_config_id |
| 000084 | Шесть таблиц личной памяти, tenants.memory_config, messages.used_memories |
| 000085 | messages.usage |
| 000086 | tenant_skills, tenant_skill_snapshots, учет установки и снимков |
| 000087 | install_session_id / install_message_id навыков, логи установки |
| 000088 | planned_name снимков, запись имени плана перед созданием |
| 000089 | envs навыков, tenant_user_env_vars |
| 000090 | tenant_skill_catalog; tenant_skills.catalog_id, обратная миграция существующих установок |
| 000091 | mcp_tool_approvals.enabled, по умолчанию true |
| 000092 | mcp_services.usage_instructions; таблица mcp_metadata, снимок инструментов сервисов MCP |
| 000093 | browser_devices, browser_pairings, browser_task_interruptions, авторизация и сопряжение устройств для браузера |
| 000094 | memory_subjects.extraction_state, memory_items.replaces_id, таблица memory_extraction_sessions (прогресс извлечения по сессиям); исправление ошибок ранней замены выводов в старых версиях |
| 000095 | memory_item_embeddings.embedding (halfvec, добавляется только при наличии расширения vector) и поисковые индексы |
| 000096 | Миграция данных: канал DingTalk изменен с режима webhook на websocket (Stream). Необходимо включить режим Stream в консоли разработчика DingTalk; down — пустая операция |
| 000097 | Форк сессий: sessions.parent_session_id / forked_from_message_id / fork_bootstrap, messages.sandbox_checkpoint |
| 000098 | Таблица fork_snapshot_leases, запись снимков песочницы перед форком сессии для последующей очистки |
| 000099 | Обновление pg_search с версий 0.22.2–0.22.5 до 0.22.6; пропускается, если образ не предоставляет 0.22.6, установлена другая версия или используется app.skip_embedding=true |
| 000100 | Удаление трех индексов в chunks, замедляющих запись: idx_chunks_chunk_type, idx_chunks_content_hash, idx_chunks_tenant_kg |
| 000101 | knowledges.profile (портрет документа), knowledge_bases.profile_config / generated_profile (AI-описание базы знаний) |
| 000102 | Таблица mcp_endpoints, эндпоинты MCP, опубликованные рабочим пространством |
| 000103 | Таблица message_artifacts, обратная миграция из messages.artifacts; далее только новая таблица. Строки с данными в старой колонке устанавливаются в NULL (колонка сохранена для совместимости при обновлении); нераспознанные file_size/created_at сбрасываются до 0 и времени создания сообщения, миграция не прерывается. Down-миграция возвращает данные в старую колонку |
| 000104 | tenant_skills.served, запись версии, предоставляемой в образе при установке или сбое |
| 000105 | messages.context_checkpoint, сжатая сводка контекста Agent |
| 000106 | Индекс для сообщений (session_id, created_at DESC, id DESC) с именем idx_messages_session_created_id, создается через CREATE INDEX CONCURRENTLY без блокировки записи; прерывание создания оставляет INVALID-индекс, перед перезапуском необходимо DROP INDEX |
| 000107 | message_artifacts.deleted_at, сохранение удаленных файлов как удаленных строк (заглушки) |
| 000108 | sessions.sandbox_config_tenant_id (BIGINT, по умолчанию 0), принадлежность конфигурации песочницы; обратная миграция для сессий, использующих общие Agent |
| 000109 | sessions.host_workspace_dir (VARCHAR(1024)), каталог проекта песочницы для Lite-версии, не меняется после создания |
| 000110 | im_channels.locale (VARCHAR(16), по умолчанию пустая строка), фиксированный язык ответа канала IM; пустая строка использует значение по умолчанию деплоя |
| 000111 | model_catalog_configs, административные переопределения каталога и последние версии истории |
| 000112 | Индексы embeddings по knowledge_id и chunk_id; обычное создание индекса, для больших таблиц перед обновлением можно предварительно создать одноименный индекс CONCURRENTLY, чтобы снизить блокировки |
| 000113 | Таблица-проекция изображений chunk_images и триггеры синхронизации; данные галереи заполняются из существующего image_info |
| 000114 | chunks.source_locators, информация для перехода к первоисточнику по цитате |
| 000115 | Обновление подходящих установленных расширений pg_search / vector до 0.25.11 / 0.8.4; для этого необходимо заранее переключить сопутствующий образ базы данных |
| 000116 | Запись пустых массивов allowed_tools исторических агентов интеллектуального рассуждения в виде явного списка инструментов по умолчанию |
| 000117 | GIN-индекс эффективных пользовательских сообщений messages.attachments для запросов сохранения ссылок на вложения |
| 000118 | Временные метки токенов и клиентов MCP OAuth переводятся в timestamptz; старые литеральные значения преобразуются как UTC |
Версии SQLite развиваются независимо и не могут напрямую сопоставляться с номерами PostgreSQL:
| Версия SQLite | Изменение |
|---|---|
| 000001–000002 | Удаление логов Wiki, пути папок |
| 000003–000004 | Автоматическая тегизация, долгосрочная память |
| 000005 | Вложения сообщений и поля приглашений |
| 000006–000008 | Задачи/dead-letters, администрирование системы, spans обработки/подсчет подзадач |
| 000009 | Флаги памяти Embed; поле не используется в интерфейсе текущего канала |
| 000010–000011 | Мультитеги, модель principal |
| 000012–000013 | usage сообщений, enabled для инструментов MCP (соответствует 000085, 000091) |
| 000014–000016 | Авторизация браузера, консистентность памяти, векторный индекс памяти (соответствует 000093–000095; в SQLite нет векторной колонки, сортировка в приложении) |
| 000017 | Канал DingTalk переведен на websocket (соответствует 000096) |
| 000018–000019 | Форк сессий, аренды снимков форка (соответствует 000097–000098) |
| 000020–000022 | Удаление индексов chunks, портрет знаний, эндпоинты MCP (соответствует 000100–000102) |
| 000023 | Таблица message_artifacts, миграция и очистка старых колонок (соответствует 000103) |
| 000024–000026 | messages.context_checkpoint, индекс времени сессий сообщений, deleted_at message_artifacts (соответствует 000105–000107) |
| 000027 | sessions.sandbox_config_tenant_id (соответствует 000108; в Lite нет общих пространств, обратная миграция не выполняется) |
| 000028 | Добавление tenant_skills, tenant_skill_snapshots, tenant_skill_catalog, tenant_user_env_vars (соответствует 000086–000090 и 000104). Ранее Lite не имел этих таблиц, что вызывало ошибку no such table |
| 000029–000030 | sessions.host_workspace_dir, im_channels.locale (соответствует 000109–000110) |
| 000031 | model_catalog_configs (соответствует 000111) |
| 000032–000033 | chunk_images и source_locators (соответствует 000113–000114) |
| 000034 | Достраивание MCP usage_instructions и mcp_metadata (соответствует 000092) |
| 000035 | Явные инструменты по умолчанию для агентов (соответствует 000116) |
| 000036 | Индекс для запросов по эффективным сообщениям с вложениями (соответствует 000117; в SQLite обычный индекс) |
Версии PostgreSQL 000099, 000112, 000115, 000118 не имеют соответствующих версий в SQLite.
Базовая схема и последующие инкрементальные миграции совместно определяют итоговое состояние новых и существующих баз данных; нельзя судить о наличии таблицы в Lite только по имени файла миграции.
Итоговая структура таблиц
Ниже представлена итоговая структура после наложения всех up-миграций (ALTER-команды для ранних таблиц объединены). Большинство бизнес-таблиц имеют поля created_at / updated_at, многие включают deleted_at (мягкое удаление GORM), они здесь не перечисляются.
Тенанты и пользователи
| Таблица | Назначение | Ключевые поля |
|---|---|---|
tenants | Тенант (рабочее пространство), корень мульти-тенантов | id (SERIAL, от 10000), name, retriever_engines (JSONB), status, storage_quota/storage_used, agent_config/context_config/conversation_config/web_search_config/credentials/api_principal_config/memory_config (JSONB), default_storage_backend_id. Колонка api_key удалена в 000065 |
users | Зарегистрированный пользователь | id (UUID), username (уник.), email (уник.), password_hash, tenant_id (FK→tenants), is_active, can_access_all_tenants (кросс-тенанты), is_system_admin (системный админ, 000053), preferences (JSON) |
auth_tokens | Токены входа | id, user_id (FK→users), token, token_type (access/refresh), expires_at (TIMESTAMPTZ, с 000072), is_revoked |
tenant_members | RBAC-членство в тенанте | user_id+tenant_id (уник. с учетом мягкого удаления), role (owner/admin/contributor/viewer), status, invited_by, joined_at |
tenant_invitations | Приглашения | tenant_id, invitee_user_id, role, status (pending/accepted/rejected), expires_at; уникальность pending; token (ссылка)/accepted_count (000054) |
tenant_api_keys | API Key тенанта/платформы | tenant_id (NULL для платформы), scope_type (tenant/platform), key_hash (уник.), full_access, knowledge_base_ids, capabilities, expires_at/revoked_at |
user_kb_pins | Закрепление базы знаний пользователем | PK (tenant_id,user_id,kb_id) + pinned_at |
user_resource_favorites | Избранное пользователя | PK (user_id,tenant_id,resource_type,resource_id) |
system_settings | Настройки системы (000053) | key, value/value_type, category, is_secret, requires_restart, last_modified_by |
audit_logs | Аудит-логи (000044) | tenant_id, actor_user_id/actor_role, action, target_type/target_id/target_user_id, request_path/request_method, outcome (success/denied), scope_type/scope_id, details (JSONB) |
Добавленная в v0.8.3 таблица model_catalog_configs хранит переопределения каталога на уровне деплоя (одна строка с id=1), версии и историю; chunk_images — запросимая проекция chunks.image_info, триггеры поддерживают ее в соответствии с записью, удалением и изменением состояния блоков. Сохранение вложений определяется ссылками на них из действительных сообщений сессии; expires_at очищает только те просроченные вложения, на которые больше никто не ссылается.
Модели и базы знаний
| Таблица | Назначение | Ключевые поля |
|---|---|---|
models | Конфигурация модели AI (LLM/эмбеддинг/реранк и т.д.) | id, tenant_id (FK→tenants), name/display_name, type (KnowledgeQA / Embedding / Rerank / VLLM / ASR), source, parameters (JSONB), is_default, is_builtin, managed_by, status |
knowledge_bases | База знаний | id (UUID), tenant_id, name, type (document/faq/wiki), chunking_config/image_processing_config/vlm_config/faq_config/asr_config/wiki_config/indexing_strategy/auto_tag_config/profile_config/generated_profile (JSONB), embedding_model_id/summary_model_id (FK→models), vector_store_id (FK→vector_stores), storage_backend_id (FK→storage_backends), creator_id (FK→users), is_temporary, activity_scope |
knowledges | Знание (документы/веб-страницы/FAQ) | id, tenant_id, knowledge_base_id (FK), type, title, source (VARCHAR(2048)), parse_status (pending/processing/finalizing/completed/failed/cancelled/deleting), pending_subtasks_count (000056), enable_status, file_name/file_type/file_size/file_path/file_hash, metadata, custom_metadata (JSONB, с 000078), folder_path (дерево папок, 000079), summary_status, profile (JSONB, портрет документа: gist/темы/тип/типовые вопросы, 000101), channel, processed_at/error_message. Без колонки tag_id — теги с 000063 связаны через knowledge_tag_relations |
chunks | Блок (единица поиска) | id, tenant_id, knowledge_base_id, knowledge_id (FK), content, source_content, content_revision, index_status, last_editor_id, context_header, chunk_index, start_at/end_at, pre_chunk_id/next_chunk_id, parent_chunk_id, chunk_type, image_info/video_info, relation_chunks/indirect_relation_chunks (JSONB), source_locators (JSONB, 000114), is_enabled, flags, status, content_hash, seq_id, tag_id |
chunk_revisions | Версии истории блоков (000078) | id, tenant_id, knowledge_base_id, knowledge_id, chunk_id+revision (уник. индекс), content, is_enabled, editor_id, edit_source, edited_at |
embeddings | Индекс векторов + BM25 (для Postgres/ParadeDB, под app.skip_embedding) | id, source_id+source_type (уник.), chunk_id/knowledge_id/knowledge_base_id, content (BM25), dimension, embedding (halfvec), is_enabled, tag_id |
knowledge_tags | Теги знаний (классификация FAQ и т.д.) | id, tenant_id, knowledge_base_id, name, seq_id |
knowledge_tag_relations | Связь документа с тегами (000063) | PK (knowledge_id,tag_id) + created_at; индексы с двух сторон |
vector_stores | Конфигурация подключения внешней векторной БД (000032) | id, tenant_id, name (уник. в тенанте), engine_type, connection_config/index_config (JSONB) |
Сессии и сообщения
| Таблица | Назначение | Ключевые поля |
|---|---|---|
sessions | Сессия (контекст диалога и снимки параметров поиска) | id, tenant_id, title, knowledge_base_id, agent_id (FK→custom_agents), user_id, max_rounds, enable_rewrite, fallback_strategy/fallback_response, keyword_threshold/vector_threshold, embedding_top_k/rerank_top_k/rerank_threshold, rerank_model_id/summary_model_id, agent_config/context_config (JSONB), sandbox_config_id/sandbox_config_tenant_id (конфигурация песочницы и принадлежащее ей пространство; 0 — собственное пространство сессии, 000108), parent_session_id/forked_from_message_id/fork_bootstrap (форк сессии, 000097; без внешних ключей), host_workspace_dir (каталог проекта настольной версии Lite, 000109) |
messages | Сообщение | id, request_id, session_id (FK), role, content/rendered_content, knowledge_references (JSONB, ссылки), agent_steps (JSONB, ход рассуждений Agent), mentioned_items/images (JSONB), is_completed/is_fallback, channel (канал web/IM), agent_id+agent_tenant_id, model_id, knowledge_id, agent_duration_ms, execution_context, attachments, used_memories/usage (JSONB), sandbox_checkpoint (снимок песочницы в точке форка, 000097), context_checkpoint (сжатая сводка контекста Agent, 000105). Колонка artifacts с 000103 больше не читается и не записывается и очищена (сохранена только для отката и rolling-upgrade); сгенерированные файлы хранятся в message_artifacts |
message_artifacts | Файлы, сгенерированные навыками, по одной строке на файл (000103) | session_id, message_id, position (порядковый номер внутри сообщения, соответствует index в API скачивания; уникален в паре с message_id), url (ссылка на хранилище или resource://, клиенту не возвращается), file_name/file_type/file_size, content_hash, source_path (один и тот же путь в одной сессии считается несколькими версиями одного файла), mod_time (текст RFC 3339, точность до наносекунд для сравнения сборщиком), created_at, deleted_at (000107: после удаления файла пользователем строка-заглушка сохраняется, чтобы position оставался стабильным и файл не собирался повторно). При мягком удалении сообщения его файлы тоже скрываются |
message_suggestion_sets | Набор предложений (000067) | tenant_id, session_id, assistant_message_id, placement (starter/follow_up), config_hash+locale (кеш-ключ, уникален), status, questions (JSONB), статистика токенов/задержки, lease_until |
message_suggestion_events | События показов/кликов предложений | suggestion_set_id (FK, CASCADE), question_id, event_type, actor_id |
temporary_documents | Временные документы сессии (000070) | tenant_id, session_id, resource_ref, file_name/file_type/file_size, status (uploaded/processing/ready/failed), content, chunks (JSONB), expires_at |
Агенты и MCP
| Таблица | Назначение | Ключевые поля |
|---|---|---|
custom_agents | Пользовательский агент | PK (id,tenant_id), name, is_builtin, created_by (FK→users), runnable_by_viewer, config (JSONB) |
mcp_services | Конфигурация сервиса MCP | id, tenant_id, name, enabled, transport_type (stdio/sse/…), url/headers/auth_config/advanced_config/stdio_config/env_vars (JSONB), is_builtin, usage_instructions (000092) |
mcp_metadata | Снимок каталога инструментов MCP (000092) | PK (tenant_id,service_id,principal), config_fingerprint, tools (JSONB), instructions, server_name/server_version/server_description, synced_at |
mcp_endpoints | Эндпоинты MCP (000102) | tenant_id, name/description, enabled, token_hash (SHA-256), knowledge_base_ids (JSONB), tools (JSONB), default_agent_id, rate_limit_per_minute, last_used_at |
mcp_tool_approvals | Политика одобрения инструментов MCP (000042) | (tenant_id,service_id,tool_name) уник., require_approval, enabled (default true) |
mcp_oauth_clients | Клиент OAuth MCP (000062) | (tenant_id,service_id) уник., client_id/client_secret/redirect_uri |
mcp_oauth_tokens | Токен OAuth MCP | (tenant_id,principal_type,principal_id,service_id) уник., access_token/refresh_token, expires_at, refresh_lease_id/refresh_lease_until (000074) |
Подключение браузера
| Таблица | Назначение и ключевые поля |
|---|---|
browser_devices | Авторизованные расширения браузера (000093), лейбл, token_hash, expires_at/renew_after, last_seen_at, revoked_at, владелец аренды |
browser_pairings | Хеш токена сопряжения с истечением |
browser_task_interruptions | Прерванные задачи для восстановления пользователем (scope_key + session) |
Песочница и навыки
| Таблица | Назначение и ключевые поля |
|---|---|
tenant_sandbox_configs | id, tenant_id, name, sandbox_type, config (JSONB), cordoned_at |
tenant_skill_catalog | Каталог навыков тенанта; name/version/description/instructions, bundle_ref/bundle_sha256 |
tenant_skills | Установка; enabled/status/error, installed_snapshot_id, installing_since, install_session_id/install_message_id, envs, served (000104) |
tenant_skill_snapshots | sandbox_config_id, skill_id, snapshot_id/parent_snapshot_id, generation, trigger/state, planned_name, superseded_at |
tenant_user_env_vars | tenant_id, principal_type/principal_id, sandbox_config_id, skill_id, name, value (шифр) |
fork_snapshot_leases | snapshot_id (PK), tenant_id, sandbox_config_id, created_at |
Долгосрочная память
| Таблица | Назначение и ключевые поля |
|---|---|
memory_subjects | (tenant_id,subject_id) уник.; enabled, block_text, item_count, extraction_state (000094) |
memory_extraction_sessions | PK (tenant_id,subject_id,session_id); прогресс извлечения |
memory_items | kind/content/topic/normalized_key, importance/origin/status, сессия/сообщение, valid_from/invalid_at/expires_at, superseded_by, replaces_id (000094) |
memory_tombstones | Удаленные/отклоненные темы и хеши содержимого |
memory_topic_stats | topic/aliases, hits, last_seen_at/promoted_at |
memory_doc_affinity | knowledge_id/knowledge_base_id/title, hits/last_used_at |
memory_item_embeddings | item_id, model_id, dims, vector |
Организации (кросс-тенанты)
| Таблица | Назначение | Ключевые поля |
|---|---|---|
organizations | Организация (000012) | id, name, owner_id (FK), owner_tenant_id, invite_code (уник.), require_approval, searchable, member_limit |
organization_tenant_members | Члены организации (000045) | (organization_id,tenant_id) уник., role, representative_user_id |
organization_join_requests | Заявки на вступление | organization_id, user_id, status (pending), requested_role, request_type (join/upgrade) |
kb_shares | Шаринг базы знаний | (knowledge_base_id,organization_id) уник., source_tenant_id, permission |
agent_shares | Шаринг Агента | FK (agent_id,source_tenant_id), organization_id, permission |
tenant_disabled_shared_agents | Отключенные шар-агенты | PK (tenant_id,agent_id,source_tenant_id) |
Wiki
| Таблица | Назначение | Ключевые поля |
|---|---|---|
wiki_pages | Wiki (000037) | id, tenant_id, knowledge_base_id, slug, title, page_type, status, content/summary, иерархия (000061: parent_slug, folder_id и др.), source_refs/chunk_refs/in_links/out_links (JSONB), version |
wiki_folders | Папки Wiki | knowledge_base_id, parent_id, name, path (материализованный путь), depth, sort_order |
wiki_page_issues | Проблемы Wiki | knowledge_base_id, slug, issue_type, description, suspected_knowledge_ids, status, reported_by |
wiki_page_revisions | История Wiki (000075) | page_id+version (уник. индекс), снапшот данных, edit_source, editor_id, edited_at |
Источники / Каналы / Поиск
| Таблица | Назначение | Ключевые поля |
|---|---|---|
data_sources | Внешние источники (Feishu/Notion/Confluence и др., 000029) | id, tenant_id, knowledge_base_id, type, config (JSONB), sync_schedule, sync_mode, conflict_strategy, sync_deletions, last_sync_at/last_sync_cursor/last_sync_result |
sync_logs | Логи синхронизации | data_source_id (FK), status, started_at/finished_at, статистика, error_message |
im_channels | Конфигурация IM | tenant_id, platform, agent_id, knowledge_base_id, mode, output_mode, session_mode, bot_identity, credentials, locale (000110) |
im_channel_sessions | Маппинг IM ↔ сессия | im_channel_id, session_id, agent_id, идентификатор пользователя/сессии платформы |
embed_channels | Встраиваемые веб-виджеты (000060) | tenant_id, agent_id, настройки токена/домена |
web_search_providers | Настройки поиска (000030) | id, tenant_id, name, provider, parameters (JSONB), is_default |
Хранилище / Ресурсы / Задачи / Наблюдаемость
| Таблица | Назначение | Ключевые поля |
|---|---|---|
storage_backends | Конфигурация объектного хранилища (000068) | id, tenant_id, name, provider, config (JSONB), source, legacy_alias |
resources | Реестр ресурсов (000069) | id, handle, tenant_id, storage_backend_id, provider, physical_path, location_hash, mime_type/original_name/size/content_hash, lifecycle (persistent/temporary)+expires_at, state |
resource_bindings | Привязка ресурсов (сообщения/знания/сессии) | (resource_id,owner_type,owner_id,relation) уник. |
resource_access_grants | Токены доступа | token_hash (уник.), resource_id, access_scope, expires_at/revoked_at |
task_pending_ops | Очередь задач (000041) | tenant_id, task_type, scope/scope_id, op, dedup_key, payload (JSONB), fail_count, enqueued_at/claimed_at |
task_dead_letters | Архив задач (dead letter) | task_type, scope/scope_id/related_id, payload, last_error, fail_count, failed_at |
knowledge_processing_spans | Трассировка обработки документов (000055) | (knowledge_id,attempt,span_id) уник., parent_span_id, name, kind, status, input/output/metadata (JSONB), error_code/error_message, duration_ms |
schema_migrations | Статус golang-migrate | version, dirty |
ER-диаграмма (основные таблицы)
Механизм миграций (golang-migrate)
Используется инструмент golang-migrate/migrate v4 (go.mod: github.com/golang-migrate/migrate/v4 v4.19.1), состояние хранится в таблице schema_migrations (version + dirty). Существуют два пути выполнения:
Автоматическая миграция при запуске (по умолчанию)
Функция initDatabase() в internal/container/container.go:
- Если
AUTO_MIGRATE != "false"(включено по умолчанию), вызываетсяdatabase.RunMigrationsWithOptions(migrateDSN, opts); - Если
AUTO_RECOVER_DIRTY != "false"(включено по умолчанию), устанавливаетсяMigrationOptions.AutoRecoverDirty = true, для автоматической попытки восстановления при dirty-состоянии; - Ошибки миграции записываются только в лог Warn и не прерывают запуск (поскольку миграции могут управляться извне), поэтому при диагностике обязательно проверяйте логи запуска;
- DSN миграции для postgres дополняется
options=-c app.skip_embedding=<true|false>(зависит от того, содержит лиRETRIEVE_DRIVERстрокуpostgres), что определяет, будут ли выполняться миграции для таблицыembeddings.
Логика выбора пути в internal/database/migration.go:
// internal/database/migration.go
migrationsPath := "file://migrations/versioned"
if strings.HasPrefix(dsn, "sqlite3://") {
migrationsPath = "file://migrations/sqlite"
}То есть postgres/ParadeDB используют migrations/versioned/, а SQLite — migrations/sqlite/.
Выполнение вручную: scripts/migrate.sh
scripts/migrate.sh является оберткой CLI migrate (цели Makefile migrate-* вызывают его):
- Автоматически загружает
.envиз корня; - DSN берется приоритетно из
DB_URL(при этомsslmode=require/preferпринудительно заменяется наdisable), иначе собирается изDB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_NAME(по умолчаниюlocalhost:5432/postgres/aihelpme), пароль кодируется с помощьюurllib.parse.quote(Python), чтобы поддержать спецсимволы; - Каталог миграций по умолчанию
MIGRATIONS_DIR=migrations/versioned; - Если
migrateне установлен, выводится подсказка:go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest.
make migrate-up # Выполнить все ожидающие миграции
make migrate-down # Откат
make migrate-version # Просмотр версии и флага dirty
make migrate-create name=add_xxx # Создание следующего файла миграции add_xxx.up.sql / .down.sql
make migrate-force version=74 # Принудительная установка версии (восстановление из dirty)
make migrate-goto version=60 # Миграция/Откат до указанной версииКак добавить миграцию
- Создание файлов:
make migrate-create name=add_my_feature, создаются файлы следующего номера версии вmigrations/versioned/(перед созданием проверьте каталог, чтобы использовать следующий номер); - Написание up SQL: учитывайте диалект PostgreSQL (JSONB, индексы,
TIMESTAMP WITH TIME ZONE); при изменении таблицыembeddingsиспользуйте условную проверкуapp.skip_embedding(аналогично существующим миграциям:SELECT current_setting('app.skip_embedding', true)), чтобы обеспечить прохождение миграций для развертываний безpostgresкак движка индексации; - Написание down SQL: миграция должна быть обратимой (drop column/table/index), иначе цепь откатов прервется;
- Синхронизация SQLite: добавьте инкрементальную миграцию с номером версии в
migrations/sqlite/, дублируя изменения (с учетом диалекта: JSONB→TEXT, SERIAL→INTEGER AUTOINCREMENT, TIMESTAMPTZ→DATETIME и т.д.). Существующие базы Lite не перезапускают000000_init, изменение только базовой схемы приведет к пропуску колонок/таблиц. Также обновите список таблиц/колонок и ожидаемую версию вinternal/database/migration_sqlite_versioned_schema_test.go; - Синхронизация моделей GORM: добавьте поля в соответствующие структуры в
internal/types/(GORM используется только для маппинга ORM, AutoMigrate для создания таблиц в production не используется, структура управляется SQL-миграциями); - Проверка:
make migrate-up→make migrate-down→make migrate-upдля подтверждения обратимости; для SQLite запустите один раз сDB_DRIVER=sqliteдля проверки скрипта инициализации Lite.
Устранение неполадок при миграциях
Порядок диагностики для production, проверки расширений и границы восстановления см. в разделе Устранение неполадок миграций БД. Команда force только изменяет маркер версии и не отменяет выполненный SQL; сначала сделайте бэкап и сверьтесь с фактической схемой БД, нельзя предполагать, что неудачная миграция была полностью отменена.
dirty state (наиболее часто)
Если миграция завершилась неудачей или процесс был убит, schema_migrations.dirty = true, последующие миграции будут отклонены.
# 1. Проверка состояния
make migrate-version # вывод вида "74 (dirty)"
# Или прямой запрос к таблице
# SELECT version, dirty FROM schema_migrations;
# 2. Остановка записи, бэкап, проверка схемы и места падения SQL
# 3. Выполнять только если схема соответствует версии 73 и миграция может быть повторена безопасно
# 73 — только пример, нельзя просто вычитать 1 из версии
make migrate-force version=73
make migrate-upПо умолчанию в приложении включен AUTO_RECOVER_DIRTY (container.go), при запуске система пытается восстановиться сама; если отключено (false), в логах будет совет использовать force.
Миграция "успешна", но таблица не создана
Проверьте логи запуска: неудачи автоматической миграции записываются как Warn (Database migration failed ... Continuing with application startup) и не останавливают процесс. Кроме того, объекты embeddings управляются через app.skip_embedding — если RETRIEVE_DRIVER не содержит postgres, отсутствие индексов embeddings является ожидаемым поведением.
Ошибки подключения из-за спецсимволов в пароле
Для CLI migrate требуется DSN в виде URL, пароли с @ # ! и другими спецсимволами должны быть URL-кодированы. scripts/migrate.sh и container.go уже обрабатывают это (используют Python quote и Go url.QueryEscape соответственно); если собираете DB_URL вручную, закодируйте его самостоятельно.
Различия ParadeDB / нативного Postgres
BM25-индексы (USING bm25, китайская токенизация Lindera) доступны только в ParadeDB; для нативного Postgres убедитесь, что соответствующие ветки миграции работают, либо используйте Elasticsearch. Инструкции по переходу существующих нативных БД Postgres на ParadeDB см. в migrations/paradedb/01-migrate-to-paradedb.sql.
Официальный образ — paradedb/paradedb:v0.25.11-pg17 (с v0.8.2 до этого использовался v0.22.6-pg17). Миграция 000115 при наличии на сервере соответствующих пакетов расширений обновляет установленные pg_search 0.22.0–0.25.10 до 0.25.11, а pgvector 0.8.0–0.8.3 — до 0.8.4; историческая миграция 000099 действует только пока используется образ v0.22.6-pg17. Другие ветки версий автоматически не обновляются и не понижаются. Каталог расширений обязан совпадать с версией образа, иначе вызов некоторых функций расширений обрушивает базу данных; ручное обновление описано в разделе Обновление существующих баз ParadeDB; на новом образе не выполняйте команду ALTER EXTENSION pg_search UPDATE TO '0.22.6'.
Конфликты файлов версий
Конфликт происходит, когда в разных ветках добавляется один и тот же номер версии: golang-migrate сортирует их по цифрам, и если в каталоге появляются дубликаты версий, он не загружается, и все развертывания падают с ошибкой миграции. При слиянии необходимо изменить номер своей миграции на следующий свободный (переименовать файлы up/down). internal/database/migration_versions_test.go загружает оба каталога versioned/ и sqlite/, конфликты выявляются в CI (000105 был перенумерован с 000104 именно по этой причине).
