Vtorum Notes — блочный заметочник с DAG-структурой: одна страница может быть размещена в нескольких ветках без создания копий.
Войдите в приложение.
Выберите пространство в левом верхнем углу.
Нажмите «+» рядом с названием пространства и создайте страницу, базу или папку.
Используйте дерево слева для навигации, а глобальный поиск — для перехода по названию и содержимому.
Ветка, которую вам выдали отдельным правом через панель «Доступ» объекта, видна в разделе «Доступные мне» вашего пространства. Раздел выглядит как папка выше всех остальных папок дерева: удалить её нельзя, сворачивается щелчком, а выданные объекты лежат в ней по пространствам и перетаскиваются в другие папки, как и раньше. Список ограничен по высоте и прокручивается. Если вы гость, показывается всё выданное вам; если вы участник пространства ветки — только права, которые вам выдал другой человек, а не все объекты пространства. Выданную ветку можно найти глобальным поиском (вместе со вложенными объектами, если право передаётся вниз) и добавить в избранное: избранное принадлежит активному пространству, а не пространству объекта. Если право отозвать, ветка пропадает из избранного. Объекты активного пространства в «Доступные мне» не дублируются — они и так в дереве.
В верхней панели обычной страницы, папки и записи БД доступна команда «В корзину». После подтверждения Vtorum открывает вышестоящий объект текущего DAG-размещения; запись возвращает в родительскую базу данных. Если удалённый объект находился только в корне, открывается первый оставшийся корневой объект дерева.
Меню «…» страницы, базы и папки всегда показывает все свои пункты целиком. Если под кнопкой не хватает места до низа окна, меню сдвигается вверх ровно настолько, чтобы поместиться; прокрутка внутри меню появляется, только когда пунктов больше, чем влезает во всё окно.
Поиск с учётом раскладки
Любой подстрочный поиск — глобальный поиск, выбор страницы и упоминание, поиск по базе и во встроенном виде, выбор записи в поле-связи и форме, выбор пользователя, значков, эмодзи, моделей, типов блоков, поиск по документации — находит слово, набранное в другой раскладке: «книга» находится и по «кни», и по «ryb», английское «river» — по «кшм». Работает и без сети. Через API подстрочный поиск (POST /v2/search) ведёт себя так же.
Клавиша Esc
На компьютере Esc закрывает верхнее открытое окно — настройки, выбор шаблона, оформление страницы, просмотр PDF, подтверждения и остальные модальные окна: нажимается кнопка «Закрыть» окна, а если её нет — срабатывает то же, что и щелчок мимо окна. Когда курсор в редакторе текста или раскрыт выпадающий список, Esc остаётся за ними и окно не закрывает.
Страница под окнами и панелями
Пока открыто модальное окно, полноэкранный просмотр или боковая панель — «Доступ», «Оглавление», история, информация о блоке, комментарии, AI-ассистент, — страница под ним не прокручивается ни колесом, ни тачпадом, ни касанием, и стрелки прокрутки страницы скрыты. Прокручивается только содержимое самого окна или панели; когда оно упирается в край, прокрутка на страницу не переходит.
Версия документации совпадает с версией приложения: 5.50.117.
Пользователь
Offline-режим и синхронизация
Установленная PWA Vtorum Notes может открывать заранее выбранные страницы, папки, базы данных и ветки дерева без сети. Данные каждого пользователя, пространства и устройства хранятся раздельно.
Откройте объект при наличии сети и нажмите облачный индикатор справа в верхнем ряду кнопок.
Включите «Доступно offline». Для папки или страницы при необходимости выберите нижележащее дерево, глубину, изображения и все файлы.
Дождитесь состояния «облако с галочкой». После этого объект можно открывать и редактировать без сети.
Для немедленной отправки локальных изменений нажмите «Синхронизировать сейчас».
Состояния индикатора
Обычное облако — объект доступен на сервере, но локальная копия не выбрана.
Галочка с маркером — есть локальная копия или ожидающие отправки изменения.
Облако с галочкой — offline-копия полностью синхронизирована.
Круговая стрелка — выполняется синхронизация после подтверждения доступности сервера.
Красное облако — сервер недоступен, а объект не имеет загруженной offline-копии; локальные изменения остаются в очереди.
Предупреждение — ошибка или конфликт, требующий решения.
Новая корневая страница создаётся без сети с постоянным локальным UUID и после первой успешной синхронизации размещается во «Входящих». Изменения блоков, заголовков, свойств записей и DAG-размещений сначала сохраняются в IndexedDB, поэтому закрытие PWA не очищает очередь.
Быстрая offline-заметка использует тот же системный раздел «Входящие», что и обычный quick input. Локальное сохранение сразу записывает страницу и текст в IndexedDB, не ожидая сетевого запроса. Если отправка была прервана ошибкой сервера, операция остаётся в локальной очереди и автоматически повторяется после восстановления соединения. При автоматическом включении «Входящих» синхронизируются структура и текст, но не скачиваются посторонние исторические вложения. Их загрузка включается только явной offline-настройкой объекта с флажками изображений или файлов.
Обновления в реальном времени
Открытая авторизованная вкладка поддерживает защищённое WebSocket-соединение с сервером. После фиксации изменений страницы, дерева или AI-задачи PostgreSQL передаёт только тип события в пределы того же рабочего пространства, а интерфейс сразу запрашивает актуальные данные. Содержимое, названия и идентификаторы объектов через канал не отправляются. Если сеть, прокси или браузер не поддерживают WebSocket, Vtorum автоматически возвращается к редкой HTTP-проверке и повторяет подключение при возврате вкладки на экран.
Локально добавленные изображения и файлы доступны сразу. Если передача оборвалась, Blob остаётся в IndexedDB: после восстановления связи или повторного запуска PWA Vtorum получает новую подписанную S3-ссылку, продолжает загрузку с тем же идентификатором и только затем отправляет блоки и свойства, которые на файл ссылаются. Явная пауза сохраняется, а отмена удаляет локальную копию очереди.
Конфликты и диагностика
При одновременном изменении одного объекта на нескольких устройствах Vtorum не затирает версии молча. В Настройки → Offline можно принять серверную версию, повторить локальную поверх актуальной, сохранить обе версии страницы или открыть объект для ручного объединения. Там же показаны очередь, ошибки, размер хранилища и технический журнал без текста заметок.
iOS может не выполнять фоновые задачи после закрытия PWA. Поэтому Vtorum всегда повторяет синхронизацию при запуске, восстановлении сети и возвращении приложения на передний план.
Обновление до новой версии
Новая версия устанавливается сама, без кнопки «Обновить». Приложение скачивает её в фоне и перезагружается в первый безопасный момент: когда вкладка скрыта (вы ушли в другую вкладку или свернули окно), при переходе на другую страницу или после минуты без ввода, если курсор не стоит в поле. Пока идёт сохранение, есть несохранённая правка страницы, не выгружена офлайн-очередь или открыто диалоговое окно, обновление ждёт — набранное не теряется. Место в базе после перезагрузки восстанавливается.
Офлайн-копия приложения — только запасной путь. Если хранилище браузера для неё сломано или недоступно (так бывает, например, в Опере), приложение просто грузится с сервера без офлайн-копии. Раньше в этом случае вместо приложения показывалась строка «Vtorum offline shell unavailable», хотя сеть была. Если она всё же появилась, закройте все вкладки Vtorum и откройте заново, а если не помогло — удалите данные сайта notes.vtorum.net в настройках браузера.
Пользователь
Дерево и несколько родителей
Страница хранится один раз, а каждое её положение в дереве является отдельным размещением. Поэтому страницу можно привязать к нескольким родителям.
Над деревом — строка навигации: «Домик», «Назад», «Вперёд», «Обновить», «Открыть в новом окне», а справа поиск, создание и сворачивание панели. «Домик» открывает стартовую страницу Vtorum (/home): тому, кто уже вошёл, она показывает рассказ о продукте и вместо формы входа кнопку «Перейти во Vtorum Notes». Туда же ведёт www.vtorum.net.
Перетаскивание меняет текущее размещение. Страницу, папку или базу можно тянуть как из дерева, так и за ручку рядом с названием в рабочей области.
«Привязать страницу» создаёт дополнительное размещение без копирования.
Ссылка на страницу или её упоминание в тексте тоже добавляет цель в дерево ещё одним размещением. Исключение — ссылка на страницу выше по ветке (родителя, раздел): она сохраняется и работает, но в дерево не добавляется, иначе ветка замкнулась бы в кольцо.
Действие «Ссылка / копия / перемещение в…» в меню «…» открывает окно, где сначала выбирают — добавить ссылку на объект в выбранную страницу (объект остаётся на месте: в странице появляется блок «Привязать страницу», а в папке — дополнительное размещение), переместить объект или скопировать его (копия кладётся в страницу или папку, в том числе другого пространства, а оригинал остаётся на месте; название копии начинается со слова «копия»). Перемещение переносит объект в найденную по названию точку назначения: страницу, папку, базу данных или запись базы — запись хранится как страница, поэтому у неё тоже могут быть дочерние объекты. Выбор базы целиком означает другое: страница переносится в базу как её запись.
«Убрать отсюда» удаляет только выбранное размещение.
Сервер запрещает циклы.
Раскрытие веток хранится по размещениям и синхронизируется между сессиями пользователя.
У иконки объекта можно выбрать цвет из 20 вариантов: откройте окно иконки, вкладку «Иконки» и нужный цвет в палитре. Дерево, избранное, шапка объекта и публикация показывают иконку выбранным цветом; кнопка «Стандартный цвет» сбрасывает выбор. Дефолтные иконки страниц, папок и баз, которые рисует система, остаются стандартного цвета.
Где видны иконки дочерних объектов. Иконка, выбранная объекту вручную, одинакова везде, кроме редактора: в дереве, в дереве публикации, в просмотре страницы и в ссылках публикации на дочерние объекты. Если иконку не выбирали, стандартный значок страницы, папки или базы рисуют только деревья — редактора и публикации, — а в просмотре и публикации ссылка остаётся без значка. В режиме редактирования ссылки на дочерние объекты значков не показывают. Иконка-эмодзи, записанная через API в формате Notion, показывается так же, как выбранная в окне иконки; пустая или незнакомая иконка считается невыбранной — дерево ставит стандартный значок.
Набор иконок содержит 1440 глифов и разделён на категории. Раздел «Люди» (97 иконок) собирает профили, роли, жесты и эмоции, «Животные» (26) — фауну и всё, что с ней связано, «Стиль жизни и ситуации» (282) — дом и быт, еду и напитки, одежду, спорт, отдых, праздники, учёбу, покупки и гороскоп. У всех иконок этих разделов русские подписи, по которым работает поиск в окне выбора иконки.
Пользователь
Страницы и блоки
Кнопка «+» открывает меню типов блоков. Нажатие на ручку перетаскивания открывает контекстное меню: в верхней строке расположены иконки комментариев, копирования, вставки, удаления и доступных для типа блока специальных действий. Названия показаны в тултипах. Блоки можно переносить, вкладывать и преобразовывать без изменения остальных частей страницы.
Пока вы печатаете в блоке, текст на экране главнее того, что страница получает с сервера: запоздавшая версия вашего же набора (ответ на сохранение, свежий снимок страницы) экран не переписывает, поэтому при быстром наборе буквы не меняются местами и не пропадают. Правка другого участника, отмена и повтор по-прежнему показываются сразу.
При перетаскивании блока бирюзовая полочка показывает, куда он встанет: перед блоком, после него, внутрь или колонкой рядом. Отпускание выполняет ровно то, что показывает полочка, где бы ни был указатель — над текстом блока, в зазоре между блоками или на полосе слева, вдоль которой ведут ручку. Над самим перетаскиваемым блоком полочка гаснет, и отпускание оставляет блок на месте. У верхнего и нижнего края окна страница сама плавно прокручивается, пока указатель там.
Картинка или аудиофайл, вставленные из буфера, становятся самостоятельным блоком, а не вложенным (безымянное аудио получает имя «Аудио-дата-время.расширение»): курсор в блоке посередине страницы — встаёт сразу после этого блока; курсор в последнем блоке или вне блоков — в конец страницы верхним уровнем. Исключение — пункт списка (маркированного, нумерованного, списка задач): там картинка ложится внутрь пункта, как и раньше, иначе она вышла бы из-под пункта и разорвала нумерацию. Так же в конец страницы верхним уровнем встают и вставленные блоки Vtorum, когда курсор не в блоке. Файлы, перетащенные мышью на середину блока, становятся вложенными; на верхнюю или нижнюю четверть — встают перед или после него. Блок, добавленный выше или ниже блока в колонке (кнопкой «+», Enter, разрезанием или вставкой текста), остаётся в той же колонке.
При создании дочерней страницы, базы или папки через тип блока редактор сначала сохраняет child-блок в текущей странице и только затем открывает созданный объект. Поэтому после возврата ссылка на дочерний объект уже присутствует в родителе.
Выделение мышью, в которое попала картинка, видео, файл, доска, схема или таблица, копируется блоками Vtorum целиком: на другой странице из него выходят такие же блоки с теми же файлами. Прежде системный буфер забирал из такого выделения только текст — имена файлов и подписи кнопок, — и вместо картинок на новом месте появлялся абзац из этих слов. Блоки, задетые выделением частично, копируются целиком. Выделение, в котором только текст, копируется как раньше.
Текст, скопированный из другого приложения, раскладывается по блокам на границах стилей: заголовок становится заголовком, элементы списка — отдельными пунктами, цитата — цитатой. Непрерывный кусок абзацев одного стиля остаётся одним блоком. Если блок, куда вставляют, пуст, он принимает стиль первого вставленного фрагмента; непустой блок сохраняет свой стиль, а текст после каретки переезжает в последний созданный блок. Оформление источника — жирность, размеры и гарнитуру шрифта — редактор не переносит: вставляется чистый текст со ссылками.
Автотекст по «@»
В любом текстовом блоке знак @ открывает список подстановок: дата, время, дата и время, имя пользователя, его e-mail, название пространства и версия Vtorum. Список сужается по мере набора — @да оставит «Дата» и «Дата и время»; Enter вставляет первую подходящую, Escape закрывает список.
Выбранное подставляется вместо «@» и набранного: сам знак в тексте не остаётся. Значение вычисляется один раз, в момент вставки, и дальше живёт обычным текстом — его можно править, копировать и находить поиском. Дата не обновится завтра: в заметке о встрече нужна дата встречи, а не дата чтения заметки. Вставленное выделено синим, чтобы отличать подставленное от набранного руками; следующий за ним текст набирается обычным цветом.
В том же списке, разделом «Люди», перечислены все, кто имеет доступ к этому объекту, — включая вас самих, поэтому отдельной строки «моё имя» среди подстановок нет: участники пространства и те, кому объект или его родитель выдан точечно. Набор сужает список и по имени, и по фамилии. Выбранное имя вставляется таким же текстом — это подпись в заметке, а не упоминание с уведомлением; чтобы сослаться на человека со связью, используйте свойство «Пользователь» в базе.
Дата и время считаются в часовом поясе из настроек профиля. Знак «@» посреди слова список не открывает — иначе он мешал бы при наборе почтовых адресов; вызовом считается «@» в начале строки или после пробела и знаков препинания.
Клавиатура
Cmd/Ctrl+Z — отмена, Cmd/Ctrl+Shift+Z (или Ctrl+Y) — повтор. Работают на всей странице, а не только когда курсор стоит в тексте: после перетаскивания блока, удаления через меню, выделения блоков целиком или закрытия диалога отмена тоже срабатывает. Страница помнит до 100 шагов; подряд набранный текст складывается в один шаг.
Своя цепочка отмены у заголовка страницы и у блока кода: там работает обычная посимвольная отмена поля ввода, и Cmd/Ctrl+Z в заголовке блоки не трогает.
В обычном тексте Enter добавляет строку. Два Enter подряд быстрее секунды разрывают блок на два по месту курсора — в любом месте текста; в конце текста так создаётся следующий блок. Медленный второй Enter или набор между ними просто переносит строку. Перетаскивалка нового блока на секунду остаётся видимой, чтобы переход был заметен.
В списке Enter создаёт следующий пункт, пустой пункт превращается в текст.
Cmd/Ctrl+Enter или Alt/Option+Enter — разбить блок на два по месту курсора: текст после курсора уезжает в новый блок того же типа, курсор переходит в его начало. Работает и в абзаце, где обычный Enter переносит строку внутри блока, и в заголовке, цитате, выноске и пунктах списка.
Cmd/Ctrl+Shift+Enter или Alt/Option+Shift+Enter — то же разделение по месту курсора, но между половинами появляется пустой текстовый блок, и курсор переходит в него. Если курсор стоит в начале или в конце блока, второй пустой блок не создаётся: пустым остаётся сам блок либо появляется единственный пустой блок ниже.
Cmd/Ctrl+/ — меню блока у курсора. Без модификатора / открывает меню только в пустом блоке, иначе дробь нельзя было бы напечатать.
Нумерация пунктов считается по подряд идущим пунктам своего уровня и одинаково работает в редакторе, в режиме чтения, в публикации и в PDF: список начинается с 1, где бы он ни стоял на странице, а абзац между пунктами начинает нумерацию заново.
Текстовый блок сам становится списком по префиксу в начале строки: -,* или + с пробелом дают маркированный список, номер с точкой или скобкой (1., 1)) — нумерованный. Префикс из текста убирается.
Tab и Shift+Tab меняют вложенность там, где это допустимо: каждое нажатие сдвигает блок ровно на один уровень вместе с его подчинёнными.
В верхнем ряду меню блока две кнопки вложенности: «Сделать подчинённым» (Tab) сдвигает блок вправо под предыдущий блок, «На уровень выше» (Shift+Tab) возвращает его назад. Место блока на странице не меняется, его подчинённые блоки двигаются вместе с ним. Меню блока и меню добавления («+») открываются под кнопкой, если там помещается хотя бы 80% их обычной высоты; иначе целиком уходят выше кнопки, а не показывают обрубок из нескольких строк.
Backspace в самом начале блока зависит от места блока на своём уровне вложенности. Первый блок уровня выходит из вложенности: он остаётся на своём месте на странице, а блоки, которые шли ниже него на том же уровне, становятся его дочерними — визуально ничего не переезжает. Второй и последующие блоки уровня сливаются с предыдущим блоком того же уровня, как и блоки верхнего уровня; пустой блок удаляется. Shift+Tab работает так же.
Протяжка мышью внутри блока — это обычное выделение текста, в любом направлении: и по горизонтали, и по вертикали по нескольким строкам блока. Выделение целых блоков начинается, только когда курсор вышел за границу исходного блока, либо сразу — если протяжка начата в служебной полосе слева от блоков.
При выделении нескольких блоков указатель у верхнего или нижнего края автоматически прокручивает длинную страницу.
Панель выделенных блоков, кроме «Тип», «Копировать» и «Удалить», несёт те же стили, что панель выделенного текста: жирный, курсив, подчёркнутый, зачёркнутый, цвет текста и цвет фона — с той же палитрой и произвольным цветом, плюс «Без цвета». Стиль ложится на весь текст каждого выделенного текстового блока: абзаца, заголовка, пункта списка, задачи, цитаты, выноски и раскрывающегося блока; картинки, код и прочие блоки не меняются. Кнопка стиля нажата, когда стиль уже стоит у всего выделенного текста, — повторное нажатие его снимает. Ссылки в этой панели нет: её ставят на конкретный фрагмент.
Окна, вызванные из редактора, закрываются кликом вне них: меню блока, боковая панель информации и истории блока, окно комментариев блока, меню упоминаний, диалог ссылки и просмотр изображения. Так же закрываются боковые панели «Доступ» и «Оглавление»; клик по их кнопке в шапке продолжает переключать панель, а клики по диалогам и оверлеям редактора панель не закрывают. Всплывающие списки самой панели — например поиск пользователей при выдаче прав — рисуются над ней в портале и тоже не считаются кликом вне панели.
Панель параметров выделенного текста закрывает любой клик вне панели — в том числе клик по самому выделенному фрагменту, — и этот же клик снимает выделение. Выделение сохраняется только при работе с самой панелью: её кнопками, палитрой цвета и диалогом ссылки. От увода курсора панель не закрывается. Сама панель всегда помещается на экране целиком: у края окна она сдвигается внутрь, у верхнего или нижнего края переходит на другую сторону выделения, а на узком экране её кнопки переносятся на вторую строку.
На телефоне и в узком окне несколько блоков выделяют режимом выделения: команда «Выделить» в меню блока выделяет этот блок и включает режим. Дальше тап по блоку добавляет его в выделение или снимает; курсор в текст не ставится, клавиатура не поднимается, ссылки и кнопки внутри блоков не срабатывают. Сверху появляется строка режима: сколько блоков выделено, кнопка «Действия» (групповое меню — тип, внешний вид, команды AI, копирование, удаление) и кнопка «Отмена». Групповое меню в этом режиме закреплено под строкой режима и при прокрутке не прыгает за блоками. Режим выключают «Отмена» в строке режима или в самом групповом меню, снятие последнего блока, касание вне редактора, смена страницы, а на компьютере — ещё и Esc. Выполненная команда меню и смена типа тоже снимают выделение. Способы выделения на компьютере — протяжка, Shift-клик, Ctrl/Cmd-клик — работают как раньше; двойное касание по тексту по-прежнему выделяет слово, вне текста — блок.
В блоке «AI-запрос» Cmd/Ctrl+Enter отправляет запрос.
Записи из Developer API V2
Фильтры и сортировки в базах данных работают по индексным значениям свойств, поэтому запись, созданная через Developer API V2, индексируется так же, как созданная в интерфейсе: по дате, тексту, числу и флажку. Записи, созданные до версии 5.1.89, можно проиндексировать разовой командой pnpm --filter @vtorum/worker records:reindexвнутри контейнера — она восстанавливает индексы из самих значений и ничего в значениях не меняет.
Иконки импортированных объектов
Buildin и Notion задают иконку объекта ссылкой на свой SVG. Такие ссылки не переносятся: вместо них импорт подбирает иконку из библиотеки Vtorum по имени и цвет из палитры (например movie_pink.svg становится «Хлопушкой» розового цвета). Если подходящей иконки нет, объект остаётся со стандартным глифом — битая картинка хуже её отсутствия. Объекты, импортированные до появления сопоставления, остаются со своими иконками: их можно выставить вручную в окне иконки.
Ссылка на объект
В шапке страницы, базы данных и папки есть кнопка «Ссылка»: она копирует адрес объекта в буфер обмена и на секунду показывает подтверждение. Формат один и тот же —/#/page/…, /#/database/…, /#/folder/…, — поэтому ссылку можно вставить в текст, чат или во внешнюю систему.
Библиотека эмодзи
На вкладке «Эмодзи» в окне иконки собраны 551 эмодзи по восьми категориям — смайлики и эмоции, жесты и руки, животные и природа, еда и напитки, спорт и активность, транспорт и места, предметы, символы — и отдельная категория «Флаги стран» со всеми 249 странами. Категории переключаются чипами, поиск ищет по названию страны и по названию категории. Превью символов крупные, по шесть в строке. В набор входят только символы, которые отображаются на распространённых системах.
Баннеры в WebP
Баннер объекта хранится в WebP: он грузится в разы быстрее, чем PNG того же качества. Браузер конвертирует картинку перед отправкой в хранилище, AI-генерация и импорт сохраняют баннер уже в WebP, а существующие обложки переводит разовая командаpnpm --filter @vtorum/worker covers:webp внутри контейнера приложения. Идентификатор файла при конвертации не меняется, поэтому оформление страниц остаётся валидным. SVG и GIF не конвертируются: вектор масштабируется сам, а анимация потеряла бы кадры.
Внешний вид страницы
В меню «…» страницы пункт «Настройки страницы» открывает окно, где есть «Внешний вид»: там выбирают цвет фона и цвет текста — из палитры в двадцать цветов или свой, любым цветом. Фон красит всю панель страницы вместе с зонами заголовка и баннера, цвет текста — заголовок, текст, кнопки и подписи. Те же цвета действуют в публикации: панель, которая обычно белая, получает выбранный фон, а все надписи и кнопки — выбранный цвет. Поле вокруг карточки публикации берёт тот же цвет с небольшим контрастом: у белой страницы оно светло-серое, у чёрной — чуть светлее чёрного.
Кнопки шапки страницы (избранное, комментарии, доступ, «…») подсвечиваются тоже цветом текста страницы: при наведении — лёгкой полупрозрачной подложкой, включённый выключатель и опубликованный доступ — подложкой поплотнее с тонкой рамкой. Поэтому иконка видна на любом фоне — и на тёмном, и на светлом. Только жёлтая метка стартовой страницы остаётся жёлтой.
Встроенные в страницу представления базы (таблица, список, карточки) и формы тоже рисуются в её оформлении — и в редакторе, и в публикации: без белой подложки, текст и рамки цветами страницы, поля ввода — лёгкой подложкой цвета текста, подсказки — приглушённым цветом текста. Цветные варианты выбора и кнопки со своей заливкой (отправка формы, запись с микрофона) сохраняют свои цвета.
Третья строка окна — «Акцентный цвет». Он заменяет бирюзовый во всех акцентах страницы: ссылки и упоминания, кнопки, выделения, активные вкладки, отметки, кнопки во встроенных базах и формах — и в редакторе, и в публикации. В отличие от фона и текста, один акцентный цвет не отключает дневную и ночную тему: страница остаётся в теме читателя, меняются только акценты. «Сбросить» снимает и его.
Панели, меню и окна (доступ, комментарии, оглавление, история) остаются на своём фоне и со своими надписями: цвет страницы в них не заходит, иначе текст в них стал бы нечитаемым. Пока у страницы выбран хотя бы один свой цвет, дневная и ночная тема к ней не применяются: она выглядит одинаково в любой теме и у любого читателя. Кнопка «Сбросить» снимает цвета и возвращает страницу под общую тему. Цвета правит тот, у кого есть право на изменение страницы; они хранятся у самого объекта, поэтому видны всем, кто её открывает.
Картинки публикаций и экспортов
Изображения, встроенные в страницы, и картинки в файловых свойствах отдаются в веб- публикациях и JSON-экспортах в WebP. Слепок делается при первом обращении к файлу и переиспользуется дальше; если исходный файл заменили, слепок пересоздаётся. Оригинал не меняется — в приложении и при скачивании файла отдаётся именно он. SVG и GIF отдаются как есть, а при сбое конвертации публикация отдаёт оригинал.
Преобразование файла в страницу
PDF, DOC и DOCX превращаются в страницу фоновой задачей: страница создаётся сразу, а текст и изображения добавляет worker за несколько секунд. Пока задача выполняется, страница показывает плейсхолдер «Готовим страницу…» с текущим этапом и сама обновляется, когда блоки готовы. Если преобразование не удалось, на месте плейсхолдера появляется причина.
Шаблоны страниц
Шаблон — это обычная страница, объявленная образцом. Из него делают новые страницы: протокол встречи, карточку проекта, дневник. Шаблон может нести одну страницу или целую ветку с базами, связями и процессами — такой шаблон называется меташаблоном (подробно — в разделе «Меташаблон: перенос устройства целиком» ниже).
База в шаблоне переносит не только список своих видов, но и выбранный вид— тот, которым она открывается. Если в оригинале база открывается доской, копия тоже откроется доской, а не первым видом по порядку. Выбранный вид базы — последний вид, выбранный её управляющим (владельцем или администратором); тот, кто вида ещё не выбирал, открывает базу им. Архивные виды в копию не переносятся.
Как сделать шаблон
Откройте страницу и выберите «Сделать шаблоном» в окне «Настройки страницы» (меню «…»).
Откроется окно «Сделать шаблоном». Если внутри страницы есть вложенные объекты, в нём выбирают, что переносить: «Только эту страницу», «Всё дерево вложенных объектов» или «Всё дерево вместе с записями баз». Вопрос задаётся, даже если ветка в дереве слева свёрнута. Второй и третий варианты делают меташаблон.
Суперадминистратор и модератор шаблонов видят в том же окне раздел «Доступность»: галочка «Глобальный шаблон» открывает шаблон всем пространствам, а «Привязать ко всем пространствам» (доступна вместе с первой) сразу добавляет его в список шаблонов каждого пространства — и тех, что создадут потом. У остальных этого раздела нет, а у страницы без вложенных объектов окно у них не открывается вовсе: шаблон объявляется сразу.
Кнопка сменится на «Это шаблон». Повторное нажатие снимает статус шаблона. Вместе со статусом снимается и глобальность: признак «глобальный», привязки к пространствам и привязка будущим пространствам. При повторном объявлении шаблон снова начинает как локальный.
Чтобы поменять вариант (например, превратить шаблон одной страницы в меташаблон), снимите статус и объявите страницу шаблоном заново.
Как применить шаблон
Создайте новую страницу. Пока в её теле ничего не сделано, под пустой строкой видна бледная панель «Применить шаблон» с иллюстрацией. Панель исчезает при первом же действии с телом страницы: вводе символа, щелчке в текст, вставке, перетаскивании файла или добавлении блока.
Нажмите на панель или выберите «Применить шаблон» в верхней панели либо в меню «…». Пункт есть только у пустой страницы, которая сама не шаблон и ещё не создана из шаблона.
В галерее найдите шаблон по подстроке названия и примените его галочкой в карточке. Значок разворота рядом открывает шаблон целиком для просмотра. Обложка карточки — средняя треть баннера шаблона по высоте. В галерее видны шаблоны пространства и глобальные шаблоны, привязанные к нему.
Галерея — общий каталог: рядом с шаблонами страниц в ней и шаблоны баз (баннер базы, значок базы, строка «База: N видов, M свойств»). Шаблон базы превращает пустую страницу в базу по шаблону — после подтверждения страница становится базой с его видами, свойствами и выбранным видом, на том же месте дерева, с теми же правами и в избранном. Как и шаблон страницы, шаблон базы даёт безымянной базе своё название, а иконку, баннер и цвета оформления — если своих у неё ещё нет. Виды копии сохраняют все настройки оригинала, включая изображение карточки: ссылки на свойства переводятся на свойства копии. Превратить можно только пустую самостоятельную страницу: без блоков и вложенных объектов, не запись базы, не папку, не шаблон и не опубликованную.
Если название странице ещё не дали (пустое или «Новая страница»), она получает название шаблона. Введённое своё название сохраняется. Дальше название меняется независимо от шаблона. Так же с оформлением: страница получает баннер шаблона, его иконку вместе с цветом и цвета фона и текста — каждое, только если своего у неё ещё нет; поставленное заранее своё остаётся. У меташаблона баннеры, иконки и цвета переносятся и на все страницы ветки. Новое название и иконка сразу видны в дереве, избранном и «Общих» — перезагружать страницу не нужно.
Защищены ли блоки, зависит от вида шаблона. Блоки обычного шаблона (одной страницы) приходят защищёнными — в режиме чтения: это копия документа, и правка текста в ней почти всегда недоразумение. Между ними и после них можно добавлять свои блоки, а чтобы сделать все блоки обычными, нажмите «Шаблон: [название]» и подтвердите разрыв связи. Меташаблон (шаблон с веткой) приходит редактируемым — и корневая страница, и вся ветка: её берут, чтобы ею работать, и запертый каталог нечем было бы поправить. Глобальность на это не влияет. В карточке галереи рядом с названием два значка: глобус или стопка листов — глобальный или локальный шаблон; бланк или карандаш — блоки придут защищёнными или редактируемыми. У значков и у кнопок «Посмотреть» и «Применить» есть подсказки при наведении.
Меташаблон вдобавок выращивает под страницей всю ветку: страницы, базы со схемами и видами, связи, триггеры и процессы (записи — если автор их разрешил). Блоки ветки не запираются. Ссылки и встроенные виды в копии ведут на объекты копии и открываются сразу, даже пока ветка не раскрыта в дереве слева; у объектов копии свои размещения, поэтому удаление блока-ссылки в копии не трогает шаблон.
Защищённые блоки нельзя редактировать, удалять, преобразовывать или переносить. Удаление исходного шаблона безопасно разблокирует его экземпляры.
Глобальные шаблоны и вкладка «Шаблоны»
Шаблон можно открыть всем пространствам — сделать глобальным; это умеют суперадминистратор и модератор шаблонов. Как устроены глобальность и привязки, описано ниже, в подразделе «Глобальные шаблоны» раздела о меташаблонах. Управляют шаблонами в Настройки → Шаблоны: у каждого значка там есть подсказка при наведении, а на телефоне рядом со значком стоит подпись.
На телефоне (ширина до 640 px) окна на большую часть экрана — «Шаблоны», галереи шаблонов страницы и базы, «Применить шаблон» и превью шаблонов (с 5.50.58) — занимают весь экран; сверху остаётся шапка с названием и крестиком, она учитывает вырез экрана. На компьютере окна прежние.
Шаблоны баз данных
База данных тоже может быть шаблоном. Механика та же, что у страниц, но переносится схема, а не содержимое.
Откройте базу и в меню «…» выберите «Сделать шаблоном».
В новой пустой базе выберите в меню «…» «Применить шаблон базы» и найдите нужный шаблон по названию.
Переносятся свойства со всеми настройками и представления с фильтрами, сортировками, группировкой и раскладкой колонок. Записи остаются в шаблоне — новая база пустая.
Связь с шаблоном видна в меню и разрывается пунктом «Разорвать связь с шаблоном».
В отличие от страниц схема созданной базы не блокируется: свойства и представления можно менять сразу. Шаблон применяется только к базе без записей, а свойства-связи и зависящие от них rollup не переносятся — они указывают на конкретную базу и её обратное свойство, поэтому в новой базе их создают заново.
Перенос блока на другую страницу
Потяните блок за ручку на страницу в дереве. Перед переносом Vtorum завершит сохранение текущей страницы, затем атомарно переместит блок, его дочерние блоки, файловые привязки и комментарии в конец страницы назначения. Папка не принимает блоки.
В пустой папке под описанием есть круглая кнопка «+» — такая же, как у блоков на странице. Она открывает то же меню, что и в заполненной папке: подстраница, база данных, папка или файл.
Описание папки — одна строка прямо под названием, как подзаголовок. Оно сохраняется само через полсекунды после ввода; Enter завершает ввод.
Вид и сортировка папки
В верхней строке кнопок папки две кнопки: вид и сортировка. Значок каждой показывает текущий выбор. Вид и сортировка привязаны к самой папке и одинаковы для всех — в редакторе, просмотре и публикации; менять их может тот, кто правит папку.
Список — строка на каждый объект и файл, как раньше.
Таблица — название, автор, даты создания и изменения.
Иконки — сетка крупных иконок с подписями под ними.
Плитки — панели в два столбца с кратким содержанием: что лежит внутри объекта (дочерние объекты, у базы — записи), сколько влезет, и «и ещё N». Если внутри ничего нет, а у самой страницы есть текст, вместо перечисления показывается его первое предложение; надписи «Пусто» нет. В публикации без дерева текст вложенных страниц не раскрывается.
Крупные плитки — те же панели на всю ширину.
Сортировка — вручную (как расставлено в папке), по названию, по дате создания, по дате изменения или по автору; направление — по возрастанию или по убыванию. Объекты при любой сортировке идут перед файлами. Ручной порядок не теряется: вернув «Вручную», вы снова увидите его. Перетаскивать объекты можно в виде «Список» с ручным порядком; в остальных видах новый объект или файл добавляет кнопка «+» — он встаёт в конец папки. В публикации файлы папки, как и раньше, не показываются, а краткое содержание плиток видно только в публикации с деревом.
Авторство и история блока
Откройте контекстное меню блока по ручке.
Нажмите «Информация о блоке», чтобы увидеть автора создания, время, последнего редактора и номер ревизии.
Нажмите «История изменений», чтобы открыть временную шкалу, сравнить две ревизии или восстановить выбранную.
Восстановление создаёт новую ревизию и не удаляет более позднюю историю.
Неизменённые блоки не перезаписываются при сохранении страницы. Поэтому редактирование соседнего блока не меняет автора и время текущего. Автосохранения одной страницы отправляются последовательно, повтор сетевого запроса идемпотентен, а собственный ответ сервера не заменяет активный текстовый DOM. Положение каретки и выделение сохраняются. При одновременном изменении одного блока в двух вкладках сервер возвращает конфликт, а изменения разных блоков сохраняются независимо.
Для импортированных блоков без достоверной исходной атрибуции интерфейс показывает соответствующую отметку.
Синхронные блоки
Скопируйте один блок через контекстное меню.
При вставке выберите «Синхронизированный блок». Если оригинал уже удалён, будет создана обычная независимая копия.
Измените любой экземпляр: содержимое автоматически обновится во всех остальных, а положение каждого блока останется локальным для его страницы.
Нажмите иконку синхронизации в контекстном меню, чтобы увидеть список «страница: блок» и перейти к нужному экземпляру.
Изменение синхронной группы требует права редактирования всех связанных страниц. Удаление отдельного экземпляра не удаляет остальные.
Полный справочник типов блоков
Ниже перечислены все типы блоков, которые редактор умеет создавать, отображать или сохранять при импорте. Техническое имя приведено для диагностики API и импортов.
Текстparagraph
Обычный многострочный текст страницы.
Enter добавляет строку внутри блока; два Enter подряд быстрее секунды разрывают блок по месту курсора (в конце текста — создают следующий блок). Cmd/Ctrl+Enter или Alt/Option+Enter разрывает блок по месту курсора в любом месте текста. Поддерживает форматирование, ссылки и упоминания страниц.
Заголовок 1heading_1
Главный раздел страницы.
Попадает в оглавление и может использоваться как якорь. Самый крупный уровень заголовка.
Заголовок 2heading_2
Раздел второго уровня.
Попадает в оглавление и формирует вложенную структуру документа.
Заголовок 3heading_3
Подраздел третьего уровня.
Используется для детальной структуры длинных страниц.
Заголовок 4heading_4
Самый компактный структурный заголовок.
Поддерживается в оглавлении и при импорте Buildin.
Маркированный списокbulleted_list_item
Перечень без обязательного порядка.
Enter создаёт следующий пункт, пустой пункт превращается в текст. Tab и Shift+Tab меняют вложенность.
Нумерованный списокnumbered_list_item
Последовательность шагов или ранжированный перечень.
Номер рассчитывается среди соседних пунктов одного уровня. Вложенные уровни нумеруются независимо.
Задачаto_do
Пункт с флажком выполнения.
Состояние флажка сохраняется в payload. Enter создаёт следующую задачу, пустая задача превращается в текст.
Цитатаquote
Визуально отделённая цитата или важная формулировка.
Многострочный текст остаётся внутри одного блока; слева показывается вертикальная полоса.
Выноскаcallout
Акцентный блок для предупреждений, итогов и пояснений.
Поддерживает иконку, фон и многострочный текст. AI-саммари страницы добавляется именно как выноска.
Раскрывающийся блокtoggle
Сворачиваемый раздел с дочерними блоками.
Дочерние блоки можно переносить внутрь перетаскиванием или клавишей Tab. Состояние раскрытия хранится в payload. Удаление раскрывающегося блока удаляет и вложенные в него блоки — и в редакторе, и через API.
Кодcode
Фрагмент исходного кода или моноширинного текста.
Заголовок в шапке включает подсветку синтаксиса: достаточно написать в нём название языка отдельным словом («Пример bash») или расширением файла («main.py»). Маркеры: js, jsx, javascript, ts, tsx, typescript, node — JavaScript/TypeScript; json, jsonc — JSON; py, python, python3 — Python; sh, bash, zsh, shell, console, terminal — оболочка; html, htm, xml, svg, vue — HTML/XML; css, scss, sass, less — CSS; md, markdown — Markdown; sql, postgres, postgresql, mysql — SQL; yml, yaml — YAML. Регистр не важен; без маркера код остаётся без подсветки. Полный список — и в подсказке «?» рядом с заголовком блока. Enter добавляет строку внутри блока.
AI-запросai_request
Диалоговый композитор для текста, генерации изображений и транскрибации аудио.
Поддерживает до 20 вложений общим размером до 150 МБ. Каждая отправка создаёт ниже неизменяемый снимок запроса и отдельные блоки ответа; повторные запросы сохраняют контекст диалога. Отказ модели не всплывает окном, а остаётся на странице: под запросом появляется блок-выноска с причиной и временем, а сам блок запроса показывает ту же ошибку до следующей отправки. Причину пишет провайдер; её код и ответ сохраняются в «Ошибки моделей» в настройках AI.
Личный сейфcrypto
Локально зашифрованный текстовый фрагмент.
Блок виден только своему автору: другим пользователям он не приходит с сервера независимо от их прав на страницу. Новые блоки используют AES-256-GCM и PBKDF2-SHA-256 с 600 000 итераций. Сервер принимает только криптографический контейнер и принудительно отбрасывает открытый текст. Пока блок разблокирован, текст остаётся в DOM и памяти браузера.
Формулаequation
Математическое выражение в LaTeX.
Редактор показывает исходное выражение и его визуальный результат через KaTeX.
Разделительdivider
Горизонтальная граница между смысловыми частями страницы.
Не содержит текста; через меню блока его можно заменить другим типом.
Ссылка на страницуlink_to_page
Ссылка на существующую страницу, базу или папку.
Отображает актуальное название целевого узла и открывает его по клику. Может создавать дополнительное DAG-размещение. Выглядит так же, как подстраница, — бирюзовой строкой того же размера, кто бы её ни поставил: человек или агент через API. Удаляется, как любой блок, из меню блока — отдельной кнопки «Удалить» в строке нет.
Дочерняя страницаchild_page
Создание или отображение страницы непосредственно под текущей.
После создания становится кликабельной ссылкой и отдельным узлом дерева. Через API v2 (PATCH /v2/blocks/{id}/children) ставится для страницы, которая уже лежит под текущей: { "type": "child_page", "child_page": { "page_id": "<id>" } } — размещение и название сервер подставит сам.
Дочерняя базаchild_database
Создание базы данных внутри текущей страницы.
База появляется в дереве и открывается как самостоятельный узел со своими представлениями. Через API v2 ставится для базы, которая уже лежит под страницей: { "type": "child_database", "child_database": { "database_id": "<id>" } }.
Дочерняя папкаchild_folder
Контейнер для дочерних узлов без собственного блочного содержимого.
Используется для организации дерева; открывается как отдельный навигационный узел. Через API v2 — { "type": "child_folder", "child_folder": { "folder_id": "<id>" } } для папки, уже лежащей под страницей.
Встроенный вид базыembedded_database_view
Представление другой базы данных прямо внутри страницы.
В payload хранятся идентификаторы базы (database_id) и представления (view_id); данные подгружаются из базы при открытии, поэтому всегда актуальны. Встроить можно и форму добавления или редактирования, кроме публичной формы — у неё есть собственная ссылка. Блок работает в режиме чтения и в публикации, где для него доступна настройка «Поиск по базе». В настройке блока один выпадающий список «Представления» с галочками: отмеченный один вид — обычный блок, два и больше — вкладки в порядке отметки, первая открывается сразу (в payload — view_id и visible_view_ids). В том же списке, когда вкладок несколько, есть «Показывать переключатель вкладок» (show_view_switcher). Так у каждой страницы свой набор видов одной базы: у руководителя — рабочие, у финансиста — свои. Переключение вкладок в блоке не меняет вид, на котором человек открывает саму базу. Размер блока задаётся ручками (как у картинки) и хранится в payload: width_px или width_percent (в колонке) и height_px; с высотой записи прокручиваются внутри блока, но только после щелчка по нему: до этого колесо над блоком листает страницу, а при наведении видна подсказка «Щёлкните, чтобы листать внутри». Активный блок отмечен бирюзовой рамкой; щелчок вне блока или Esc возвращают колесо странице. Без заданной высоты блок растёт вместе с содержимым и листается со страницей.
Интеллект-картаmindmap
Дерево тем от корневой страницы с ветвями, которые можно связать со страницами.
Узлы добавляются, переименовываются, сворачиваются и перетаскиваются; ветвь можно превратить в дочернюю страницу и открыть её по клику. Корневой узел показывает название текущей страницы. При открытии карта сама встаёт так, что корень оказывается в центре окна; кнопка с прицелом рядом с «+» и «−» (подсказка «Центрировать корень») возвращает корень в центр в любой момент — масштаб при этом не меняется. Кнопка есть и в режиме просмотра, и в публикации; во время работы с картой положение сбивается не само, а только при открытии и по кнопке. Payload версии 1 хранит root_id и список узлов.
Схема Mermaidmermaid
Блок-схема, диаграмма последовательности и прочие схемы, записанные текстом Mermaid.
Сверху поле с текстом схемы на языке Mermaid, снизу — область отображения: картинка перерисовывается сама через мгновение после правки. Ошибку разбора блок показывает строкой под картинкой, оставляя прежний рисунок на месте. Текст схемы хранится в payload (editor_text) так же, как у блока кода, поэтому находится поиском; в экспорт Markdown схема уходит блоком ```mermaid. Тема рисунка следует теме приложения. В публикации читатель видит только саму схему — без текста Mermaid и кнопки копирования; в редакторе и просмотре внутри Vtorum текст остаётся. Схема рисуется до 2000 связей и 200 000 знаков текста (у Mermaid по умолчанию 500 и 50 000); пределы задаёт Vtorum, директивой в тексте схемы их не поменять. Окно кода растёт по тексту, но не выше квадрата (высота равна ширине блока), дальше текст прокручивается; окно схемы — квадрат. Размер обоих окон настраивается: под каждым окном полоса-ручка — потяните её вниз или вверх, либо наведите на неё фокус и нажмите стрелку вверх или вниз (шаг 24px); двойной щелчок по ручке возвращает размер по умолчанию. Высота от 96 до 2400px сохраняется в самом блоке и одинакова у всех в редакторе, просмотре и публикации (в публикации ручек нет). Длинный текст и крупная схема прокручиваются внутри окон. Схема по умолчанию вписана в окно целиком; масштаб меняют кнопки «−» и «+» в углу окна, Ctrl/⌘ + колесо мыши или щипок на тачпаде (к точке под указателем), кнопка с процентами снова вписывает схему. Мышью увеличенную схему можно двигать перетаскиванием. Так же схема ведёт себя в просмотре и публикации. Код схемы можно свернуть в одну строку кнопкой «Свернуть» в шапке блока (в строке видна первая строка схемы) и развернуть кнопкой «Развернуть» или щелчком по строке; выбор сохраняется в блоке. Карта смыслов из меню текстового блока приходит со свёрнутым кодом.
Изображениеimage
Растровое или поддерживаемое браузером изображение.
Загружается в S3, поддерживает изменение ширины, просмотр в галерее и подпись. Массовый выбор создаёт последовательные блоки.
Видеоvideo
Видеофайл, воспроизводимый непосредственно на странице.
Загружается в S3, отображается HTML5-проигрывателем, поддерживает подпись, замену, изменение ширины и размещение в колонках. Поддерживается в режиме чтения и публикации.
Файлfile
Скачиваемое вложение любого разрешённого типа.
Показывает имя, размер и подпись; файл хранится в S3. Вложение можно заменить без удаления блока. Массовый выбор обрабатывается через очередь загрузки. Блок загрузки, которая ещё идёт, удалить сохранением страницы нельзя (отменяют загрузку в очереди); если загрузка оборвалась (закрыли вкладку, пропала сеть) и шесть часов не двигается, блок удаляется как обычный, а раз в час сервер сам помечает такие загрузки «не удалась».
PDFpdf
Постраничный просмотр PDF непосредственно внутри страницы.
Показывает страницу документа как изображение, листается стрелками снизу, изменяет ширину ручкой как изображение и открывается во встроенном полноэкранном PDF-просмотрщике по клику (пока он открыт, страница под ним не прокручивается), кнопки просмотра остаются на месте и не гаснут — в любой момент, сколько бы страница ни была открыта: просмотрщик получает свежую ссылку на файл при каждом открытии. Кнопка «Скачать» в просмотрщике сохраняет файл на диск сразу, не открывая его новой вкладкой и поверх страницы — в том числе когда Vtorum установлен приложением; так же работают «Скачать» у картинок, в чате и у файлов в свойствах базы. Файл до 300 МБ сохраняется целиком из памяти браузера с исходным именем, более крупный — по ссылке-вложению. Связь страницы с её файлами база записывает сама при любой записи блока — в том числе в копиях страниц, шаблонах и импорте: по этой связи решается доступ к файлу, офлайн-загрузка и уборка хранилища. Файл, добавленный на страницу через API, показывается с именем и расширением и открывается встроенным офисом или просмотрщиком PDF так же, как загруженный вручную. Скачанный файл приходит со своим настоящим типом — презентация открывается как презентация, таблица как таблица; запасное имя файла для программ, не понимающих русских имён, записано латиницей, а не прочерками. PDF-файловый блок можно превратить в PDF-блок без повторной загрузки файла. PDF больше 2 ГБ онлайн не показывается: браузерный просмотрщик такой документ не открывает, поэтому вместо просмотра в окне — сообщение «PDF слишком большой для online-просмотра» и кнопка «Скачать» (шапка со «Скачать» и закрытием остаётся), а PDF-блок вместо превью страниц пишет, что документ слишком большой для предпросмотра. Превью страниц сервер строит, скачивая документ на диск, а не в память, и держит его несколько минут, чтобы листание не качало файл заново.
Закладкаbookmark
Внешняя ссылка в компактном блоке.
Открывается в новой вкладке; при импорте сохраняет исходный URL и подпись.
Встраиваниеembed
Ссылка на внешний встраиваемый ресурс.
В текущем безопасном режиме отображается как внешняя ссылка, если источник нельзя встроить напрямую.
Доска для рисованияdrawing_board
Бесконечная белая плоскость для схем, фигур, текста и соединителей.
Поддерживает мышь, стилус и касания, двухпальцевое перемещение, pinch-to-zoom, undo/redo, полноэкранный режим и привязку стрелок к сторонам фигур. В «Оформлении» объект переключается между передним планом и фоном: подложку стрелки не обходят, а рисуется она под остальными объектами.
Встроенный HTMLhtml_embed
Готовая HTML-страница внутри записи.
Содержимое берётся из HTML-файла или скачивается по ссылке и сохраняется вместе с записью, поэтому не зависит от жизни источника. Показывается без рамок, ширина и высота настраиваются ручками, как у изображения. В меню блока есть «Скачать» и галочка «Блок во всю высоту»: с ней высоту задаёт сама страница и блок кончается там же, где она. Своей прокрутки у такой страницы нет: колесо над блоком листает страницу целиком. Ссылки на другие сайты открываются новой вкладкой, а ссылки-якоря внутри самой страницы прокручивают документ Vtorum к нужному разделу: во всю высоту встроенная страница показана целиком и своей прокрутки не имеет. Страница работает в изолированной песочнице: до данных и окна приложения её скрипты не дотягиваются.
Колонкаcolumn
Горизонтальная раскладка соседних блоков.
Создаётся переносом блока в боковую зону или через меню. Ширины колонок можно менять; на узком экране они складываются вертикально.
Таблицаtable
Простая таблица внутри страницы, обычно импортированная из Buildin.
Поддерживает строки, ячейки и признаки заголовочной строки или колонки. Кнопки «Строка» и «Колонка» добавляют новую строку под текущей ячейкой и новую колонку справа от неё (для выделенного диапазона или объединённой ячейки — после последней её строки и колонки), а не в конец таблицы. Не заменяет полноценную базу данных. Таблица всегда видна целиком и листается вместе со страницей; внутри прокручивается только по горизонтали, когда колонки шире страницы. Панель оформления выбранной ячейки держится у верхнего края экрана, а строка действий («Строка», «Колонка», удаление, «Первая строка — заголовок») — у нижнего, пока таблица на экране. Окна «Цвет текста» и «Фон» закрываются кликом мимо них и клавишей Esc; открытое второе окно закрывает первое. Высота ячейки следует за её текстом: сузили колонку — ячейка вырастает, и перенесённая строка не прячется под край. Текст, выделенный внутри ячейки, копируется как обычный текст (а не вся таблица) и вставляется в другую ячейку только текстом: блоки из буфера в ячейку не вставляются.
Строка таблицыtable_row
Дочерний блок таблицы с ячейками одной строки.
Отдельно от таблицы не существует: в редакторе строки добавляются самой таблицей, а в Developer API V2 передаются детьми блока table. Ячейки хранятся массивом в payload.
Оглавлениеtable_of_contents
Автоматический список заголовков текущей страницы.
Обновляется по заголовкам уровней 1–4; клик прокручивает страницу к выбранному разделу.
Хлебные крошкиbreadcrumb
Путь размещения текущей страницы.
Показывает кликабельных родителей. При нескольких родителях в шапке виден один путь, остальные открываются кнопкой «Ещё пути». Пути через объекты в корзине не показываются: вести по ним некуда. У объекта, который сам в корзине, путь остаётся — его смотрят как раз там.
Шаблонtemplate
Сохранённый при импорте структурный блок шаблона.
Отображается как диагностически сохранённое содержимое; исходные данные не теряются.
Синхронизированный блокsynced_block
Импортированное представление синхронизируемого содержимого.
Vtorum сохраняет текст и исходный payload; создание нового такого блока вручную пока недоступно.
При создании блок подписывается автором: сохраняются имя, время, SHA-256 документа и отпечаток открытого ключа. Блок одинаково показывает отпечаток, хэш и кнопку «Проверить подпись» в редакторе, в режиме чтения, в публикации и в PDF. Проверка открывается окном поверх документа — и в приложении, и в публикации, — так что место в документе не теряется; в шапке окна рядом с крестиком стоит кнопка «Открыть отдельной страницей» — она ведёт на адрес вида /verify/<идентификатор> для тех, у кого доступа к документу нет. На копии приветственной страницы подпись относится к оригиналу и помечена как копия со ссылкой на проверку оригинала. Криптографическая часть появляется в блоке сразу после сохранения страницы, перезагружать её не нужно.
Неподдерживаемый блокunsupported
Безопасное сохранение неизвестного типа из внешней системы.
Показывает диагностическую карточку и хранит исходный payload, чтобы данные не исчезли и могли быть повторно обработаны после добавления поддержки.
Пользователь
Доска для рисования
Блок «Доска» поддерживает мышь, сенсорный ввод и стилус. Обычный и скруглённый прямоугольники имеют разные пиктограммы. Удаление выбранного объекта обозначено корзиной, а очистка всей доски — отдельным ластиком и требует подтверждения.
Рабочая область является бесконечной белой плоскостью без границ листа.
Фигуры перемещаются и изменяют размер, соединители могут быть привязаны к фигурам.
Один палец или стилус работает выбранным инструментом; два пальца перемещают плоскость, а щипок масштабирует её относительно центра жеста.
При появлении второго пальца незавершённый штрих отменяется, поэтому жесты навигации не создают дублирующие линии.
Панель инструментов на узком смартфоне переносится на компактные ряды и не требует скрытой горизонтальной прокрутки.
Доступны undo/redo, полноэкранный режим и команда показа всех объектов, включая расположенные за прежними границами.
В режиме чтения и публикации автоматически показывается весь итоговый рисунок.
Колесо мыши и тачпад над доской на странице прокручивают страницу; масштаб доски — с Cmd/Ctrl. На весь экран колесо работает с самой доской.
Объекты копируются и вставляются: Cmd/Ctrl+C копирует выделенный объект, Cmd/Ctrl+V вставляет копию рядом с оригиналом (каждая следующая — дальше по диагонали). Правая кнопка мыши открывает меню доски вместо меню блока: на объекте — «Копировать», «Вставить» и «Удалить», на пустом месте — «Вставить», и копия ложится в точку клика. Скопированное можно вставить и на другую доску, в том числе в другой вкладке. Стрелка, скопированная без своих фигур, вставляется свободной.
Поставив фигуру, текст или стрелку, доска возвращается к инструменту «Указатель» — следующий клик мимо не ставит ещё один объект. Карандаш остаётся включённым: рисуют обычно несколькими штрихами подряд. Нажатие на существующий объект в режиме фигуры или текста выделяет его и сразу позволяет перетащить, переключая доску на указатель.
Текст в блоке — цвета его границы. Подпись стрелки стоит у самой линии — на середине её пути: над горизонтальным участком, сбоку от вертикального.
Выравнивание по соседним блокам: пока блок тащат, его левый и правый края и центр, а также верх, низ и середина прилипают к таким же линиям соседних блоков, если до них меньше 6 пикселей экрана, и появляется розовая линия выравнивания. При растягивании за угол так же прилипают правый и нижний край. Удерживайте Alt, чтобы тащить без прилипания.
Delete (или Backspace) удаляет выделенный объект и в доске на странице, и на весь экран; Cmd/Ctrl+Z и Cmd/Ctrl+Shift+Z тоже работают в обоих режимах.
Толщина рамки у блоков и текста задаётся от 0 — блок без рамки. У штрихов и стрелок минимум — 1, иначе их не было бы видно.
Окно оформления объекта — текст, выравнивание, шрифт, цвета, тип и толщина линии, слой — открывается тремя способами: двойным кликом по объекту, кнопкой с карандашом в панели инструментов и мини-кнопкой (кружок с карандашом) у правого верхнего угла выделенного объекта. Если объекты лежат друг на друге, двойной клик открывает свойства верхнего — того, что виден и выделен. Поле текста в окне — на всю ширину, в две строки. Кнопка оформления, кружок изменения размера и ручки концов стрелки не зависят от масштаба доски: на экране они всегда одного размера.
Пользователь
Файлы и массовая загрузка
Файлы можно выбрать через блок или перетащить мышью из проводника прямо в поле редактора. Изображения, видео и остальные файлы создаются отдельными последовательными блоками и передаются в серверную очередь в исходном порядке. Максимальный размер одного файла и одного пакета — 1 ГиБ.
Перетащите один или несколько файлов в редактор и отпустите их над подсвеченной зоной либо создайте блок «Файл», «Изображение» или «Видео» и выберите файлы через системный диалог.
Перед запуском очереди Vtorum сохраняет текущие изменения страницы, затем создаёт блоки там, где стояла зелёная полочка в момент отпускания: перед блоком, после него или внутри него. Если отпустить файлы над зазором между блоками, полочка встаёт у ближайшего блока — туда они и лягут. Только когда полочки нет, блоки создаются в конце страницы.
Обычный файловый блок открывается или скачивается по клику. Для замены откройте меню по ручке блока и нажмите иконку «Заменить файл»: блок сохранит положение и идентификатор, а файл и метаданные обновятся.
Подменю «Сменить тип блока» показывает только безопасные смены — без потери данных, с сохранением текста, форматирования и файла. Текстовые блоки (текст, заголовки 1–4, списки, задача, цитата, выноска, раскрывающийся блок) переходят друг в друга; без форматирования (жирный, курсив, ссылки, упоминания, цвет) — ещё в «Код» и «Формулу». «Код» переходит в текстовые блоки и «Схему Mermaid», «Схема Mermaid» — в «Код», «Формула» — в текстовые блоки и «Код». «Изображение», «Видео», «PDF» и «Встроенный HTML» переходят в «Файл»; «Файл» — в изображение, видео, PDF или встроенный HTML по типу и расширению файла (картинка, ролик, PDF, HTML). Пустой блок и «Разделитель» меняются на любой тип. У остальных блоков (AI-запрос, таблица, mindmap, доска, сейф, закладка, ссылки на страницы, дочерние объекты, встроенная БД, синхронный блок, подпись) смены типа нет, и подменю не показывается. У выделенной группы блоков кнопка «Тип» предлагает только типы, в которые без потерь переходит каждый блок группы (пересечение их безопасных смен); если общих типов нет, кнопки нет.
Строка «Сменить тип блока» в меню блока — обычная (белая) строка, а не контекстная команда; подменю типов открывается и остаётся открытым, даже если у нижнего края страницы меню при этом перескакивает выше кнопки и курсор оказывается за его границей.
Двойной клик (на сенсорных экранах и в узком окне — двойное касание) по тексту блока выделяет слово под курсором; блок целиком выделяется двойным кликом по его полю вне текста, а также рамкой, Shift-кликом и Ctrl/Cmd-кликом.
Вторая строка меню блока — панель внешнего вида (Ж, К, Ч, З, цвет текста и фона, как у выделенного текста): она есть у текстовых блоков (текст, заголовки, списки, задача, цитата, выноска, раскрывающийся блок) и применяется ко всему тексту блока. Выделенная группа блоков показывает то же меню: панель внешнего вида — только если все блоки группы текстовые, смена типа — по пересечению безопасных смен, частные команды (WebP, объединение с соседями, сброс ширины, файл в медиа) — только если подходят каждому блоку группы; команды AI группы — те, что подходят каждому блоку: у текстовых блоков команда выполняется по объединённому тексту всех блоков группы (результат встаёт под последним блоком), у картинок и файлов — отдельно для каждого (у каждого своя задача и своя заглушка). Верхний ряд меню группы един: копировать, удалить, разделитель и внешний вид. Меню стоит над выделением (не закрывая его блоки), пока оно есть.
Команды AI в меню блока («Транскрибация», «Иллюстрировать», «Сделать summary», «Озвучить», «Создать карту смыслов», «Описать») показываются, только если для них настроены модели: текстовые команды — текстовая модель (или модель суммаризации), «Иллюстрировать» — текстовая и графическая, «Транскрибация» — модель транскрибации, «Озвучить» — TTS-модель; функция «Запрос AI» должна быть включена.
В меню блока (ручка слева) над поиском типов стоят команды AI. У файла со звуком — «Транскрибация»; у текстового блока (абзац, заголовок, список, цитата, выноска) — «Иллюстрировать» (картинка по тексту), «Сделать summary», «Озвучить» (до 5000 символов) и «Создать карту смыслов» (текстовая модель строит дерево-схему Mermaid слева направо со стрелками от общего к частному; если ответ модели оборвался на полуслове, оборванная последняя строка отбрасывается, а схема остаётся рабочей, и под блоком появляется блок «Схема Mermaid» с уже нарисованной картой, а её код свёрнут в строку); у блока-картинки и блока-PDF — «Описать». Команда не создаёт ни блок «AI-запрос», ни блок с промптом: задача ставится на сам блок, а результат (картинка, аудио, текст) сразу встаёт под ним, без подписи-промпта; саммари кладётся одной выноской без заголовка. Пока команда выполняется, на месте результата стоит блок-заглушка: заголовок команды, время работы и журнал действий (задача принята, воркер взял её в работу, какая модель ответила, замена заглушки); по готовности заглушка заменяется целевым блоком, а при ошибке — выноской с причиной. Заглушку можно удалить как обычный блок. Нужны подключённый AI и включённая функция «Запрос AI». У PDF описание строится по тексту документа, а у скана — по распознанному тексту. Длинные записи (дольше 15 минут) режутся на фрагменты автоматически.
В проигрывателе звука (файловый блок, свойство «Аудио», комментарии, публикация) справа от времени стоит кнопка скорости: каждое нажатие переключает 1× → 1.25× → 1.5× → 2× → 0.75×. Выбранная скорость запоминается и действует для всех записей. Место, где вы остановили запись (пауза, уход со страницы, закрытие вкладки), тоже запоминается: в следующий раз воспроизведение начнётся с него; дослушанная запись начинается сначала. Скорость и место хранятся в этом браузере и на другие устройства не переносятся.
Откройте Настройки → Загрузки, чтобы видеть пакет и каждый файл.
Очередь позволяет приостановить, продолжить или отменить пакет. Если браузер был закрыт до передачи локальных файлов, выберите их повторно в очереди: совпадение выполняется по имени и размеру.
Файлы FB2 открываются по клику во встроенной полноэкранной читалке. В ней доступны светлый, тёмный и сепия-стили, кнопка скачивания, клавиатурное перелистывание и свайп вправо/влево на мобильных устройствах. Vtorum запоминает позицию чтения конкретной книги для авторизованного пользователя; в веб-публикации читалка работает без входа и сохраняет позицию в текущем браузере. При открытии FB2 Vtorum учитывает кодировку из XML-заголовка и BOM, поэтому книги в UTF-8, Windows-1251 и других поддерживаемых браузером старых кодировках отображают кириллицу без символов замены.
Любое видео и любой файл больше 5 МиБ загружаются через долговечную очередь даже при одиночном выборе. Видеоблок воспроизводит поддерживаемые браузером форматы, позволяет менять ширину и может размещаться в колонках так же, как изображение. Формат и кодек должны поддерживаться конкретным браузером.
В контекстном меню видеоблока есть строка «Установить превью»: выбранная с компьютера картинка приводится к пропорциям самого видео (по краям симметрично добавляются чёрные поля, изображение не обрезается), переводится в WebP и сохраняется в объектном хранилище. Превью накладывается поверх кадра с кнопкой воспроизведения, по нажатию исчезает и запускает видео, а его видимый размер всегда равен размеру блока — при ресайзе блока превью меняется вместе с видео. Оно показывается и в режиме просмотра, и в веб-публикациях. Рядом доступны «Заменить превью» и «Удалить превью».
Для PDF доступен отдельный блок «PDF». Он показывает первую страницу как иллюстрацию, стрелка снизу слева листает назад, стрелка снизу справа — вперёд, а ручка в правом нижнем углу меняет ширину блока так же, как у изображения. Клик по странице открывает штатный полноэкранный PDF-просмотрщик. У файлового блока с PDF в контекстном меню есть выделенная команда «Превратить в блок PDF» — исходный asset сохраняется, повторная загрузка не нужна. У файлового блока с HTML-страницей (.html, .htm) в контекстном меню есть команда «Превратить в блок»: файл становится блоком «HTML-страница» и показывается на странице в рамке, тот же файл остаётся в хранилище и копируется заново не будет. Если до первого PDF-блока в содержимом объекта нет изображения, его первая страница считается первой иллюстрацией объекта: она используется в карточках БД (включая Галерею и Доску) и как social preview публичной страницы, в том числе для Telegram. Если выше PDF находится изображение, приоритет остаётся у изображения.
Для загруженных PDF, DOC и DOCX в контекстном меню файлового блока доступно действие «Превратить в страницу». Vtorum размещает новую дочернюю страницу справа от файла в колонках 50/50 и сохраняет текущую позицию прокрутки. PDF обрабатывается Poppler: каждый лист рендерится отдельным изображением в высоком разрешении, блоки идут подряд и помечены «сливать с соседями» — без подписей и вертикальных интервалов, поэтому страница читается как показ слайдов. Текстовый слой в блоки не переносится: поиск по содержимому обеспечивает индексирование изображений, которое подхватывает листы само. DOC/DOCX обрабатываются LibreOffice Writer; изображения сохраняют размер, таблицы становятся нативными табличными блоками.
Перед созданием блока сервер проверяет размер объекта в файловом хранилище. Пустые или неполные файлы не считаются завершёнными.
Пользователь
Базы данных
Запись базы является обычной страницей с набором свойств. Поддержаны таблица, список, доска, галерея, календарь, аналитическое представление «График» и публичные формы.
В настройках записываемого свойства можно задать типизированное значение по умолчанию. Оно применяется при создании новой записи, а явно введённое значение имеет приоритет.
Вид хранит фильтры, сортировку, группировку, порядок и видимость полей.
Цвет строки в таблице: в настройке вида («Вид») выберите перечислимое поле — выбор, статус или множественный выбор, — и каждая строка окрасится в цвет своего значения, тот же пастельный, что у плашки значения, колонки доски и карточки календаря. У множественного выбора решает первый вариант; пустое значение и вариант без цвета строку не красят. Выделенная строка остаётся заметной, в тёмной теме цвет приглушён, чтобы текст читался. Окраска действует и во встроенных видах, и в публикации.
Порядок колонок таблицы — свой у каждого вида. Колонку, в том числе «Название», перетаскивают за ручку в заголовке: меняется порядок только в этом виде, а не порядок свойств базы. Редактор, встроенный просмотр и публикация показывают один и тот же порядок — из раскладки вида (property_layout); свойства, которых в раскладке нет, идут следом в порядке базы. В редакторе «Название» видно всегда: через него открывают запись. Ширину колонки тянут за правый край заголовка в редакторе — встроенный просмотр и публикация показывают ту же ширину; колонка при этом остаётся на своём месте и ровно той ширины, какую задали: свободное место справа остаётся пустым, колонки не растягиваются — поэтому база, встроенный вид и публикация выглядят одинаково. Встроенный в страницу вид обновляется сам: изменения порядка, ширины, фильтров и записей базы появляются в нём без перезагрузки страницы. Порогов «не уже» нет: любую колонку, и «Название» тоже, можно сузить до 40 px (уже край не ухватить, чтобы растянуть обратно). Без настройки — 180 px, у «Названия» — 380 px. Если таблица шире блока, она прокручивается вбок; если уже — колонки остаются своей ширины, а свободное место справа занимает пустая колонка (цвет строки доходит до края).
Вкладки представлений растут по высоте: длинное название переносится на несколько строк, и весь ряд вкладок становится выше — по самой высокой.
База открывается на том представлении, которое человек выбрал в ней последним. Если выбора ещё нет (новая база, копия из шаблона), открывается первое представление, показывающее записи; формы при этом пропускаются — это конструкторы анкет, а не список записей. Форма откроется первой, только если других представлений у базы нет.
На доске дочерние записи (связь базы на саму себя) показываются деревом под родительской карточкой, если попали в ту же колонку. Настройка «Всегда показывать родителя» добавляет родителя и в чужие колонки — бледной «тенью»: только название, без свойств и картинки, а дети под ней. Тень появляется независимо от группировки и фильтров вида: даже если сама родительская запись в выборку не попала. В своей колонке родитель остаётся обычной карточкой.
Для галереи и доски настройка «Не обрезать длинный текст» показывает текстовые свойства карточек полностью, с переносом на несколько строк.
Тип свойства «Галерея» хранится и работает как «Файлы» — та же загрузка, формы, выгрузки и тени, — но в карточке записи картинки показываются лентой с горизонтальной прокруткой, а не ссылками на скачивание; файлы, не являющиеся картинками, остаются ссылками под лентой. Переключение типа между «Файлы» и «Галерея» не стирает значения — в отличие от смены типа на любой другой.
Картинка из свойства «Галерея» или «Файлы» открывается по щелчку в полноэкранном просмотрщике — с листанием по всем картинкам значения, увеличением и кнопкой «Скачать», — и в карточке записи, и в таблице, и в публикации. Остальные файлы открываются вкладкой по постоянному адресу: он не устаревает, поэтому вкладка, открытая вчера, или скопированная из неё ссылка открываются и через сутки. Сами вложения хранятся бессрочно.
Тип свойства «Аудио» хранит записи списком и показывает каждую своим проигрывателем (с 5.44.3; раньше — одну). В режиме правки рядом кнопка микрофона «Записать»: браузер спросит разрешение, пока идёт запись, видны красная точка, время и столбики уровня с микрофона — по ним видно, что голос действительно пишется; повторное нажатие останавливает запись и сохраняет её в свойство. Во время воспроизведения столбики у проигрывателя двигаются. Запись из браузера не несёт длительности — проигрыватель вычисляет её сам; Safari пишет в MP4, остальные браузеры — в webm (opus). Можно и загрузить готовый аудиофайл. Новая запись добавляется к прежним — можно наговорить несколько подряд; удаляется каждая отдельно, крестиком рядом с её проигрывателем. В публичной форме новая запись пока заменяет прежнюю. Записывать можно в карточке и на странице записи, в таблице, во внутренних и публичных формах (в публичной форме свою запись можно прослушать до отправки); в публикации свойство показывается проигрывателем без записи. Если у поля формы задано условие показа, а в момент отправки оно не выполнено, поле скрыто и запись в него не сохраняется.
У «Аудио» есть настройка «Автоматическая транскрибация». Когда запись сохранена, AI расшифровывает её, и текст ложится в конец тела записи под заголовком «Транскрибация: название свойства · дата и время записи». У каждой записи своя расшифровка, она появляется по готовности; новая запись прежние расшифровки не трогает. Длинные записи режутся на куски по 4 минуты. Если модель «зацикливается» — повторяет одну фразу подряд, — кусок переспрашивается, а оставшиеся повторы схлопываются до одного. Каждая запись расшифровывается автоматически один раз: неудачная попытка не повторяется при каждой правке записи, чтобы не тратить деньги на модель. Модель транскрибации и подсказки берутся из настроек AI («Автоматическое саммари» → модель транскрибации); для записи из публичной формы используются настройки AI владельца формы.
«Изображение карточки» в оформлении вида умеет брать иллюстрацию из файлового свойства базы — типов «Файлы» и «Галерея»: выберите «Файл из свойства …» — первой картинке из значения свойства достанется место иллюстрации. Файлы, не являющиеся картинками, пропускаются; если картинок в значении нет, карточка остаётся без изображения.
У таблицы в оформлении есть переключатель «Показывать картинки в файловых полях»: с ним картинка в файловом поле отображается миниатюрой прямо в ячейке, а не ссылкой на скачивание. Щелчок по миниатюре открывает файл; прочие файлы остаются ссылками. Рядом — переключатель размера картинок: маленький в высоту строки, средний вдвое выше, большой вчетверо.
В веб-публикации связи с непубликованной базой остаются замаскированы. Если связанная база сама опубликована, вместо маски показываются реальные названия её записей; это правило действует и для встроенных в страницу представлений БД.
Логотип пространства: владелец пространства может поставить свой знак вместо знака Vtorum рядом с названием — в настройках, в карточке пространства. Логотип видят все участники; по умолчанию стоит знак Vtorum, и кнопка «Вернуть знак Vtorum» возвращает его. Принимается картинка до 5 МБ, лучше квадратная.
Тень в другом пространстве: кнопка «Тень / копия в пространство» в шапке объекта создаёт синхронизированную копию объекта и всего его дерева в выбранном пространстве. Тень только для чтения: правки делаются в оригинале и разъезжаются по теням. Смотреть тень могут все участники пространства, где она стоит, — доступ к оригиналу им не нужен. Создать тень может любой, у кого есть доступ на чтение объекта. Удаление тени оригинал не затрагивает; у тени и у оригинала с тенями кнопка подсвечена фоном. Если оригинал отправить в корзину или стереть, его тени исчезают во всех пространствах.
Копия в другом пространстве: вторая половина той же кнопки. В окне выбирается, что сделать — тень или копию, — и пространство. Копия собирает объект и всё его дерево на новом месте один раз и связи с оригиналом не имеет: её правят как обычный объект, а правки в оригинале до неё больше не доходят. Поэтому копию можно положить и туда, где тень этого же объекта уже стоит. Список пространств для копии короче, чем для тени: копия — это создание объекта, поэтому нужно право создавать объекты в пространстве-приёмнике, а не только состоять в нём.
Файлы при копировании в другое пространство: картинки, видео, PDF и другие файлы копии дублируются — в хранилище делается собственная серверная копия каждого файла, а в пространстве копии заводится его запись. Ссылки в блоках, значках, баннерах и значениях свойств переписываются на эти копии, поэтому копия не зависит от оригинала: удаление файла в исходном пространстве её не ломает, а публикация копии отдаёт все файлы. Раньше копия ссылалась на файлы оригинала, в приложении они открывались, а в публикации картинки и PDF были «недоступны». Файл больше 5 ГБ при копировании не дублируется (ограничение серверной копии в S3), о нём пишется в журнал. Файлы копируются по четыре одновременно. Пока идёт копирование, в окне видна полоса хода — «Копируем файлы: 12 из 31 · 8 ГБ из 20 ГБ» — и кнопка «Отменить»: после отмены новые файлы не берутся, уже скопированные убираются, а сама копия объекта уходит в корзину нового пространства (её можно восстановить или очистить). Для API: `POST /api/nodes/:id/copies` принимает необязательный `progressKey` (UUID), по которому `GET /api/nodes/copies/:key/progress` отдаёт ход, а `POST /api/nodes/copies/:key/cancel` прерывает работу; отменённый запрос отвечает 409 с кодом `copy_cancelled`.
График: в настройках представления выбираются ось категорий, разбивка на серии и величина. Кроме количества записей доступны количество значений, количество уникальных значений (с указанием поля уникальности), количество и доля пустых или заполненных значений, сумма, среднее, медиана, минимум, максимум и размах. Арифметическим величинам нужно числовое поле-основание, остальным подойдёт любое свойство. Агрегацию считает база данных, поэтому график не зависит от количества записей.
Экспорт JSON: в табличном виде нажмите Экспорт, включите «Экспорт в JSON» и скопируйте публичный URL. Ответ — массив объектов только с названиями и значениями видимых полей, в фильтрации и сортировке текущего вида. Параметры URL с названием поля, например ?Статус=Готово, добавляют точное условие равенства через AND и поэтому могут только сузить выборку.
Подписка на календарь: в календарном виде выберите поле даты, нажмите отдельную кнопку Экспорт на панели представления, включите подписной календарь компактным переключателем и скопируйте HTTPS-ссылку для Google Calendar либо нажмите кнопку Apple Calendar. Канал динамически учитывает фильтры этого вида и доступен только для чтения. Секретную ссылку можно отключить или перевыпустить; любой, у кого она есть, видит названия и даты событий.
«График» строит столбчатые, горизонтальные, линейные, площадные и кольцевые диаграммы по текущей базе; поддерживает count, sum, average, min, max, серии и группировку дат.
Вид «Форма добавления» создаёт анкету. Для каждого поля настраиваются порядок, подпись, подсказка, обязательность, скрытое значение и условие показа. Каждая отправка создаёт обычную запись базы.
Вид «Форма редактирования» работает с существующими записями и состоит из трёх шагов: поиск, таблица найденных и правка выбранной записи. Шаги настраиваются на отдельных вкладках конструктора и открываются последовательно: таблица — после заполнения поиска, форма правки — нажатием на строку. Текстовые поля поиска сопоставляются вхождением, остальные — точным совпадением; условия поиска складываются с преднастроенным фильтром таблицы, а не заменяют его. Видимые поля правки показывают значения открытой записи, умолчание формы подставляется только в пустое поле, а скрытые поля пишут своё значение всегда.
Форма внутри Вторум даёт возможность тому, у кого прав на изменение базы нет: достаточно доступа на чтение. Взамен действуют границы, которые проверяет сервер — писать можно только в поля формы, скрытые поля заполняет сервер, а править можно только записи, проходящие преднастроенный фильтр формы и фильтр её представления. Автором изменения остаётся сам человек. Подробно — в разделе «Формы базы данных».
У формы есть режим доступа: «публичная ссылка» или «только внутри Вторум». Во втором случае публичной ссылки нет, а представление вставляется в страницу блоком «Представление базы данных» — доступ к странице даёт доступ к форме. Форма редактирования публичной ссылки не получает ни при каком режиме и всегда работает правами вошедшего человека.
В фильтрах представлений и в скрытых значениях форм у полей «Пользователь» доступно значение «Я»: оно разворачивается в того, кто выполняет запрос или создаёт запись. Там, где заполняющий неизвестен, такое условие не находит ничего.
В форме доступны поля «Связь» и «Пользователь». Связь заполняется подстрочным поиском по названиям записей той базы, на которую ссылается свойство: посетитель видит названия, запрос отдаёт не больше двадцати совпадений за раз. Пользователь выбирается из списка участников пространства — только имена, без почты.
Публичная форма добавления не раскрывает записи и настройки базы. Файлы загружаются по одноразовым токенам, а повторные запросы защищены idempotency и rate limits. Внутри Вторум файловые поля в формах недоступны — файлы кладут прямо в запись.
Блок «Встроить БД» показывает выбранный ранее созданный вид прямо внутри страницы, а база отображается дочерним объектом в DAG. Размер меняется ручками, как у картинки: правая — ширина, нижняя — высота, угловая — обе сразу. Если задана высота, записи прокручиваются внутри блока; в колонке ширина считается в процентах колонки. Двойной щелчок по угловой ручке возвращает размер по содержимому. Заданный размер действует и при чтении, и в публикации.
Записи можно размещать в дереве как дочерние страницы.
Доступ и публикация базы распространяются на её записи согласно настройкам наследования.
Полный справочник типов полей
Техническое имя указано для API, импорта и диагностики. Значения по умолчанию доступны только записываемым полям и применяются при создании записи; явно переданное значение всегда имеет приоритет.
Названиеtitle
Значение: Строка; одновременно является названием страницы-записи.
Настройки: Обязательное системное поле каждой базы. Удалить или сменить тип нельзя.Поведение: Используется в ссылках, relation, поиске, дереве и карточках представлений.
Текстrich_text
Значение: Произвольный текст, включая многострочный.
Настройки: Можно задать текст по умолчанию для новых записей.Поведение: Поддерживает текстовые фильтры, сортировку и редактирование непосредственно в таблице. Через API значение записывается фрагментами в формате Notion: {"rich_text": [{"type": "text", "text": {"content": "План и факт"}}]}; plain_text передавать не обязательно — сервер берёт текст из text.content (у упоминания — из имени). Хранится одной строкой, поэтому оформление фрагментов не сохраняется.
Числоnumber
Значение: Конечное целое или дробное число.
Настройки: Значение по умолчанию; стиль отображения (число, звёздочки, линейный или круговой индикатор); маска вывода — знаков после запятой: «Как записано» или 0–10 (1148200 при двух знаках показывается как 1148200,00, разделитель — запятая, разрядов маска не добавляет); выравнивание — слева, по центру или справа. Через API: {"number": {"format": "number", "decimals": 2, "align": "right"}}; неверные decimals или align — ошибка 400.Поведение: Участвует в числовых сравнениях, сортировке, формулах, диаграммах и агрегатах rollup. Маска меняет только показ: хранится и считается число как есть. Маска и выравнивание действуют в таблице, карточках, на странице записи, во встроенных видах, в публикации и в поле связанной записи; при вводе поле показывает само число.
Автоинкрементauto_number
Значение: Порядковый номер записи, который выдаёт сама база.
Настройки: Настроек нет: номер назначается при создании записи. При добавлении поля в непустую базу уже существующие записи нумеруются по их текущему порядку.Поведение: Значение нельзя изменить ни в интерфейсе, ни через API. Удаление записи не возвращает её номер в оборот: следующая запись получает следующий номер, а не освободившийся. В фильтрах, сортировке и диаграммах ведёт себя как число.
Выборselect
Значение: Один вариант из настроенного списка.
Настройки: Для вариантов задаются названия и цвета; доступно значение по умолчанию.Поведение: В таблице показывается цветной меткой. Поддерживает группировку, фильтрацию и доску.
Множественный выборmulti_select
Значение: Массив из нуля или нескольких вариантов.
Настройки: Использует общий список цветных вариантов; по умолчанию можно выбрать несколько.Поведение: Отображает несколько меток и поддерживает фильтры по наличию значений.
Статусstatus
Значение: Один вариант состояния.
Настройки: Варианты настраиваются аналогично select; можно выбрать начальный статус.Поведение: Предназначен для этапов процесса, поддерживает доску, группировку, фильтры и сортировку.
Датаdate
Значение: Начало и необязательное окончание периода в ISO-формате; время может отсутствовать.
Настройки: Значение по умолчанию задаётся двумя способами: конкретной датой либо правилом «сегодня со сдвигом в днях» (например, сегодня + 2 дня — типовой срок исполнения). Правило вычисляется в момент создания записи, поэтому не устаревает назавтра, как записанная календарная дата.Поведение: Используется календарным видом, iCalendar, фильтрами по диапазону и группировкой дат. Ввод: щелчок по дате открывает календарь — месяц со стрелками (щелчок по названию месяца открывает выбор месяца и года), дни с понедельника, сегодня отмечено рамкой, выбранный день залит; щелчок по дню выбирает дату, внизу «Сегодня», «Завтра» и «Очистить». Цифры с клавиатуры вводят дату прямо в поле («13.09.2026», «13092026», «1.9.26» — точки ставятся сами), стрелки ↑/↓ сдвигают её на день, с Shift — на неделю. Время необязательно: у заполненной даты через символ от неё значок часов; щелчок открывает окно выбора времени — крупно выбранное время, быстрые варианты (09:00, 12:00, 15:00, 18:00, «Сейчас»), сетка часов и минут с шагом 5 минут (выбор минут закрывает окно) и «Без времени». Выбранное время (не 00:00) показывается рядом с датой вместо часов; щелчок по нему снова открывает окно, а точное время набирают прямо в поле («1430», «9:05»), стрелки ↑/↓ меняют его на 15 минут, с Shift — на час. Время 00:00 считается «без времени». Так же устроены поле даты в фильтрах и время запуска в триггере «время».
Флажокcheckbox
Значение: Логическое значение: да или нет.
Настройки: По умолчанию может быть включён или выключен.Поведение: Редактируется одним нажатием; поддерживает условия «отмечено/не отмечено».
URLurl
Значение: Строка веб-адреса.
Настройки: Можно задать адрес по умолчанию.Поведение: Отображается как безопасная внешняя ссылка; опасные схемы не исполняются.
Emailemail
Значение: Строка адреса электронной почты.
Настройки: Можно задать адрес по умолчанию.Поведение: Показывается как контактное значение и сохраняется отдельно от учётных записей Vtorum.
Телефонphone_number
Значение: Строка номера в пользовательском формате.
Настройки: Можно задать номер по умолчанию.Поведение: Формат не преобразуется, поэтому сохраняются код страны, добавочный номер и оформление.
Пользовательpeople
Значение: Массив идентификаторов пользователей: участников пространства и людей с доступом к записи.
Настройки: Можно выбрать одного или нескольких пользователей по умолчанию.Поведение: Назначить можно участника пространства или человека, которому выдан доступ к самой записи — через право на неё, на её базу или на родительский объект (например, внешнему финансисту открыли страницу финмодели, не приглашая его в пространство). Такие люди есть в выборе и в поиске с пометкой «доступ к объектам»; «Я» (@me) в формах и фильтрах разворачивается в них так же, как в участника. Сервер проверяет каждого нового человека в поле; если доступ отозвали, значение остаётся в записях как история, но выбрать человека заново нельзя. Удалённые пользователи не могут быть назначены.
Файлыfiles
Значение: Массив файлов Vtorum с идентификатором, именем, MIME-типом и размером.
Настройки: Можно выбрать файлы по умолчанию из текущего пространства.Поведение: Файлы связываются с записью через S3-активы, доступны в формах и сохраняют контроль доступа базы.
Аудиоaudio
Значение: Аудиозаписи: массив файлов Vtorum (идентификатор, имя, MIME-тип, размер) — хранится так же, как «Файлы». С 5.44.3 записи накапливаются: новая добавляется в конец.
Настройки: Галочка «Автоматическая транскрибация» (в API — audio.auto_transcribe): расшифровка записи ложится в тело записи.Поведение: Везде показывается проигрывателем. В режиме правки — кнопка микрофона «Записать» (идёт запись — красная точка и время, повторное нажатие останавливает), загрузка аудиофайла и удаление; новая запись заменяет прежнюю. Работает в карточке и на странице записи, в таблице, во внутренних и публичных формах; в публикации — только проигрыватель.
Настройки: Выбирается база назначения; при создании можно добавить взаимное поле и его название.Поведение: Цели проверяются сервером. Взаимная relation автоматически обновляется при добавлении и удалении связей. Окно выбора записи открывается поверх страницы с курсором в поле поиска — название можно сразу печатать.
Поле связанной записиlinked_property
Значение: Вычисляемое значение того же типа, что выбранное поле-источник.
Настройки: Выбираются relation-поле и поле связанной базы.Поведение: Повторяет значение связанной записи без ручного копирования и пересчитывается при изменении источника или relation. Поле только для чтения.
Формулаformula
Значение: Вычисляемая строка, число, логическое значение или пустое значение.
Настройки: Ссылки на поля записываются как {Название поля}. Поддержаны числа, строки, true/false/null, скобки, + − * / %, сравнения, =, !=, &&, || и функции if, concat, round, min, max, abs, length, empty, lower, upper. Для числового результата — «Вывод числового результата»: знаков после запятой (как записано или 0–10) и выравнивание, как у «Числа». Через API: {"formula": {"expression": "…", "decimals": 2, "align": "right"}}.Поведение: Формула проверяется при сохранении и пересчитывается по зависимостям. Правка одной записи пересчитывает только вычисляемые поля и читает связанные записи одним запросом; неизменившееся значение не перезаписывается и не поднимает ревизию. Деление на ноль, циклы и неизвестные ссылки возвращают ошибку; поле только для чтения. В окрашенной строке таблицы ячейка формулы берёт цвет строки, как и остальные.
Rolluprollup
Значение: Вычисляемый результат по значениям записей, доступных через relation.
Настройки: Выбираются relation, поле целевой базы и функция: количество, непустые, сумма, среднее, минимум, максимум, уникальные или исходные значения. Для числового результата — знаков после запятой и выравнивание, как у «Числа»; через API — decimals и align в блоке rollup.Поведение: Тип результата определяется полем-источником и функцией: show_original сохраняет исходный тип, числовые агрегаты возвращают число, unique — набор значений. Пересчитывается автоматически и не редактируется вручную. Когда меняется связанная запись, пересчёт ссылающихся записей идёт в фоне: правка отвечает сразу, а значения rollup и полей связанной записи у сотен ссылающихся записей обновляются в течение нескольких секунд.
Дата созданияcreated_time
Значение: Дата и время создания записи.
Настройки: Системное поле без значения по умолчанию; тип и значение менять нельзя.Поведение: Заполняется сервером и подходит для фильтров, сортировки, календаря и аналитики.
Создалcreated_by
Значение: Пользователь, создавший запись.
Настройки: Системное поле только для чтения.Поведение: Формируется из аудита записи и не заменяется при последующем редактировании.
Дата измененияlast_edited_time
Значение: Дата и время последнего изменения записи.
Настройки: Системное поле только для чтения.Поведение: Автоматически обновляется сервером и может использоваться как поле даты в представлениях.
Изменилlast_edited_by
Значение: Пользователь последнего изменения.
Настройки: Системное поле только для чтения.Поведение: Автоматически отражает последнего редактора записи.
Вид «График»
График — аналитическое представление базы: он не показывает записи, а считает по ним величину и рисует диаграмму. Настраивается в панели представления.
Тип диаграммы: столбчатая (bar), горизонтальная (horizontal_bar), линейная (line), площадная (area) и кольцевая (donut).
Ось категорий — по какому свойству делить записи: выбор, статус, дата, название, текст, число, флажок, пользователь, формула, rollup и системные поля создания и изменения. У дат выбирается шаг: автоматически, день, неделя, месяц, квартал или год.
Серии — второе свойство, разбивающее каждую категорию на части (у кольцевой диаграммы серий нет). Серий показывается не больше двенадцати.
Величина: количество записей, количество значений, количество уникальных значений, количество и доля пустых или заполненных, сумма, среднее, медиана, минимум, максимум, размах. Сумме, среднему, медиане, минимуму, максимуму и размаху нужно числовое поле-основание (число, автоинкремент, формула, rollup); остальным подойдёт любое свойство.
Отбор и порядок: сортировка по названию категории или по величине в обе стороны, предел числа категорий и переключатель «показывать пустые значения» (категория «Без значения»). Когда ось — дата, график показывает все значения выборки: это ряд, и его период задаётся фильтром представления, например «последние 30 дней». Предела числа категорий у такой оси нет, иначе он отрезал бы как раз свежие дни.
Ширина: столбчатый, линейный и площадной графики укладывают все точки в ширину экрана. Когда точек много, подписи дат и значений прореживаются так, чтобы не налезать друг на друга; последняя точка подписана всегда, а значение любой точки видно при наведении.
Оформление: подписи значений, легенда, сетка, накопление серий друг на друге (stacked) и цветовая схема — фирменная, бирюзовая или разноцветная.
Величину считает база данных одним запросом, а не браузер по загруженным записям, поэтому график одинаково быстр и на сотне записей, и на сотне тысяч. Фильтр и поиск представления учитываются.
Через API график — обычное представление с "type": "chart", а его настройки лежат в layout: chart_type, category_property_id, value_property_id (или "__count__" — количество записей), aggregation, series_property_id, date_granularity, sort, limit, include_empty, show_values, show_legend, show_grid, stacked, color_scheme. Свойства называются идентификатором или ключом схемы базы.
Ссылка на базу в шапке карточки возвращает на то же место, откуда запись открыли: то же представление, та же страница таблицы, а сама запись подводится к середине экрана — её видно сразу. Если записи в списке уже нет (удалили, перестала подходить под фильтр), возвращается запомненная прокрутка. Место запоминается по ходу прокрутки и при уходе в карточку, помнится полчаса и применяется один раз: следующее открытие базы снова начнётся с того места, где вы остановились, а через полчаса — с начала.
Завершающие действия в карточке — удаление записи, перенос в другую базу и превращение в страницу — тоже возвращают туда, откуда запись открыли: на страницу со встроенным видом — к той же прокрутке, в базу — к тому же месту представления. Удалённой или перенесённой записи в виде уже нет. Если карточку открыли напрямую (по ссылке, после перезагрузки вкладки), удаление и перенос ведут в базу, а превращение оставляет на получившейся странице — как раньше. Место помнится полчаса в пределах вкладки.
Скрытое свойство
Галочка «Скрывать свойство во всех представлениях и карточках» в настройке свойства убирает поле с глаз, не удаляя значений. Скрытое свойство не показывается колонкой таблицы и строкой в карточках доски, списка, галереи и календаря, не предлагается в фильтре, сортировке и настройке вида. В карточке записи оно видно в режиме «Видимые», только если заполнено, и всегда — в режиме «Все». Название записи скрыть нельзя.
Уже сделанный выбор скрытие не отменяет: доска, сгруппированная по скрытому полю, строит колонки по нему — и в редакторе, и во встроенном виде, и в публикации. Поля форм скрываются своей настройкой формы, этот признак на формы не влияет.
Через API: GET /v2/databases/{id} отдаёт у каждого свойства "hidden": true или false; PATCH принимает { "properties": { "Раздел": { "hidden": false } } } (а также { "config": { "hidden": false } } или внутри блока типа). Признак вливается в настройки свойства, не логическое значение — ошибка 400.
Уникальность записей
Дубль в учёте ломает расчёт молча: две статьи с одинаковым набором признаков — и разноска не знает, куда относить проводку. Уникальность задаётся на двух уровнях и проверяется при каждой записи — в таблице, карточке, формах, API и в процессах.
Уникальное свойство — галочка «Уникальное значение» в настройке свойства: у двух записей не может быть одинакового значения. Доступна у названия, текста, числа, выбора, статуса, даты, адреса, почты, телефона и связи.
Составной ключ — меню «…» базы → «Уникальность записей»: набор до шести свойств, уникально их сочетание («Юнит + ЦКП + Направление + Тип»). Условие делает ключ частичным: «только среди активных» — выключенную статью можно оставить и завести новую.
Повтор не сохраняется: таблица возвращает прежнее значение и показывает «Такая запись уже есть: «…» — совпадает …». Правила сравнения:
запись, у которой пусто хоть одно поле ключа, не проверяется — черновики не мешают друг другу;
записи в корзине не считаются;
текст сравнивается без учёта регистра и крайних пробелов, связь — набором записей;
включить уникальность на базе, где повторы уже есть, нельзя — появится список повторов: сначала их нужно исправить.
Через API: признак — { "ИНН": { "unique": true } } в properties того же запроса (вливается в настройки свойства, в схеме базы отдаётся как unique), ключи — unique_keys в PATCH /v2/databases/{id}. Отказ — ответ 409unique_violation с id и названием двойника в details. upsert_key у приёмника процесса records_create может называть ключ базы — тогда запись с тем же сочетанием обновляется, а не создаётся.
Форма — это представление базы, через которое человек добавляет или правит записи, не получая прав на изменение самой базы. Видов два: форма добавления (form) — анкета, каждая отправка создаёт запись, и форма редактирования (edit_form) — три шага: поиск, таблица найденных, правка выбранной записи. Настраиваются они в конструкторе вида, а через API — полем layout представления (подробно ниже).
Где форма работает
Режим доступа — access: "public" (по публичной ссылке, заполняет кто угодно) или "workspace" (только внутри Вторум). Форма без настройки считается публичной — так работали формы до появления режима. Встроить в страницу и отправлять изнутри можно только форму "workspace": у публичной есть своя ссылка, второй вход с другими правилами не нужен. Форма редактирования публичной не бывает.
Внутреннюю форму вставляют в страницу блоком «Встроить БД» (или embedded_database_view через API) — доступ к странице ведёт к форме.
Ссылка на форму редактирования с заполненным поиском. К адресу страницы, где встроена форма, добавляются параметры после «?»: https://notes.vtorum.net/#/page/<страница>?view=<id вида формы>&Сделка=<id записи>. Поле поиска узнаётся по id свойства, его внешнему ключу, имени свойства или подписи поля (регистр не важен). Связь и «Пользователь» принимают id через запятую, выбор и статус — id или название варианта, флажок — 1/да, число — число, остальное — текст. view необязателен: он переключает блок на нужную вкладку и прокручивает к нему; без него значения получит любая форма на странице с таким полем. Если значения пришли, поиск выполняется сразу. Права не расширяются: поиск идёт правами вошедшего с рамкой формы и фильтром вида, а запись из ссылки в поле связи сервер сверяет с условием поля — неподходящая не подставляется, форма пишет «Запись из ссылки не подходит для поля…». Такой адрес можно хранить в поле «URL» записи или собирать формулой — щелчок по нему в таблице откроет форму с этой записью.
Права. Человеку нужен доступ на чтение базы: форма добавляет ему возможность писать, но не читать. Поиск формы редактирования — обычный запрос к базе от имени человека, поэтому рамка формы ограничивает, что можно править, а не что можно прочитать. Если читать базу целиком сотрудникам нельзя, выдайте им отдельную базу-вход или делайте разграничение фильтром по «Я» в самих видах, которые им показываете, — и помните, что прямой запрос к базе такие виды не ограничивают.
Что проверяет сервер
Границы формы держит сервер, а не браузер — прислать можно что угодно:
пишутся только поля, включённые в форму; всё остальное из запроса отбрасывается;
скрытое поле заполняет сервер значением из настройки; присланное браузером на его месте игнорируется;
обязательное видимое поле без значения — отказ;
поле, скрытое условием показа, не обязательно и не записывается — условие считается на сервере по тем же значениям, что уйдут в запись;
форма редактирования правит только записи, которые проходят и рамку формы (edit_form.table.filter_ast), и фильтр самого представления. Проверка идёт при каждом сохранении;
«Я» ("@me") в значениях и в рамке разворачивается в того, кто отправляет форму. Автором записи и изменения остаётся сам человек.
Отправка идёт тем же путём, что правка в таблице: пересчитываются формулы, rollup и поля связанной записи, выдаётся доступ по полям «Пользователь», пишется история значений, и просыпаются правила — «создание» у формы добавления, «изменение» и «изменение поля» у формы редактирования, «изменение связанной записи» у тех, на кого запись ссылается.
Поле формы
Поля перечисляются массивом fields; порядок в массиве — порядок в форме. Свойства базы, которых в массиве нет, форма добавляет в конец включёнными (форма поиска — выключенными), поэтому служебные поля перечисляйте явно с "enabled": false.
Ключ
Что задаёт
property_id
Свойство. Через API можно писать property — имя, ключ схемы или UUID.
enabled
false — поля в форме нет вовсе.
label
Подпись вместо имени свойства.
description
Пояснение под подписью.
placeholder
Подсказка внутри поля — у текста, числа, адреса, почты, телефона, связи и пользователя.
required
Обязательное.
hidden
Скрытое: не показывается, значение подставляет сервер.
default_value
Значение по умолчанию. У скрытого поля — единственное; у видимого подставляется, и человек может его поменять.
condition
Условие показа: { property_id, operator, value }. Операторы: equals, not_equals, contains, empty, not_empty, checked, unchecked. У выбора сравнивается id варианта.
relation_filter
Только у поля-связи: из каких записей связанной базы можно выбирать. Условия ставятся по полям связанной записи — подробнее ниже.
default_from
Умолчание из записи, выбранной в другом поле-связи этой формы: { field, property } — подробнее ниже.
Условие на связанную запись
Поле-связь по умолчанию предлагает любую запись связанной базы. Условие сужает выбор: «Ответственный — только люди с признаком “мужчина”», «Проект — только открытые». В конструкторе формы это блок «Выбирать только записи, у которых» в карточке поля-связи: свойство связанной базы, оператор и значение; условий может быть несколько — «все сразу» или «любое из них».
Условие действует дважды. В поле формы человек видит только подходящие записи, а при отправке сервер проверяет каждую выбранную: запись не из связанной базы или не прошедшая условие — отказ 400 «В поле «…» выбрана запись, которая не подходит под его условие». Работает в форме добавления (и публичной, и внутри Вторум) и в полях правки формы редактирования.
Через API relation_filter пишется теми же словами, что фильтр запроса к базе, с именами свойств связанной базы, или готовым деревом { "operator": "and", "conditions": [...] }. Сервер переводит его в дерево с UUID свойств; незнакомое свойство — ошибка 400, у поля не-связи ключ не принимается.
Значение из выбранной записи
У базы есть связи с «Договором» и с «Контрагентом», а у договора — свой контрагент. Поле «Контрагент» формы можно заполнять само: после выбора договора в него подставится контрагент этого договора. В конструкторе — «Заполнять из выбранной записи» в карточке поля: там перечислены поля-связи формы и совместимые свойства связанных баз (того же типа, у связей — ссылающиеся на ту же базу; название и текст взаимозаменяемы).
у видимого поля значение подставляется сразу после выбора, и человек волен его поменять;
у скрытого поля значение считает сервер при сохранении — по записи, выбранной в поле-источнике (у формы редактирования, если источник не меняли, — по сохранённой);
если связь допускает несколько записей, берётся первая выбранная; запись должна проходить условие поля-источника.
Через API — default_from: field — поле-связь этой базы, property — свойство связанной базы; оба по имени, ключу схемы или UUID. Несовместимый тип — ошибка 400.
текст, адрес, почта, телефон — строка; число — число; флажок — true/false;
выбор и статус — вариант из схемы базы: { "id": "…", "name": "Черновик", "color": "…" }; множественный выбор — массив таких вариантов;
дата — { "start": "2027-03-01", "end": null } или правило «сегодня со сдвигом» { "relative": "today", "offset_days": 0 }: оно разворачивается в день на момент заполнения, а не хранится датой настройки;
layout в PATCH заменяет настройки вида целиком: передавайте все нужные ключи сразу, а текущие берите из GET /v2/database-views/{id}.
Ввод голосом
В настройках формы добавления есть галочка «Ввод голосом». Когда она включена, сверху справа в форме — во внутренней и в публичной — появляется круглая кнопка микрофона. Нажатие открывает окно записи: браузер спросит доступ к микрофону, столбики показывают уровень сигнала, «Остановить и распознать» заканчивает запись.
Запись голоса.
Отправка записи на сервер.
Расшифровка речи моделью транскрибации.
Разбор сказанного по полям формы текстовой моделью: она видит видимые поля формы (текст, числа, даты, флажки, выбор из вариантов) и возвращает только то, что было сказано; вариант выбирается дословно из списка, относительные даты («завтра») считаются от сегодняшнего дня. Каждое значение модель подтверждает цитатой, и оно принимается, только если цитата действительно звучит в записи, говорит словами, а не одним счётом («раз, два, три» ничего не заполнит), и в её предложении названо само поле. Сомнительное поле остаётся пустым — его заполняют руками. Связи, пользователи и файлы голосом не заполняются.
Поля заполнены — человек проверяет значения глазами, правит при необходимости и сохраняет форму. При сохранении расшифровка ложится в текст созданной записи под заголовком «Голосовой ввод».
Все шаги видны в окне; при ошибке — её причина и кнопка «Записать заново». Модели берутся из настроек AI («Автоматическое саммари»: модель транскрибации и текстовая модель): во внутренней форме — того, кто заполняет, в публичной — владельца формы, и расход идёт с его подключения. В публичной форме запись видит только тот, кто её сделал (по ключу задачи).
Настройка формы редактирования
layout.edit_form состоит из трёх частей — по шагу формы:
search — поиск: title, description, submit_label, require_value (по умолчанию true: пустой поиск ничего не ищет, иначе форма превращается в выгрузку базы; к форме без полей поиска это не относится), fields (как выше; текст ищется вхождением, остальное — точным совпадением; скрытое поле поиска — постоянное условие) и layout — дерево «И / ИЛИ»: { "kind": "group", "operator": "or", "children": [{ "kind": "field", "property": "Название" }, …] }, до трёх уровней. Если видимых полей поиска нет, шага поиска нет вовсе: форма сразу показывает найденные записи — всё, что пропускает рамка формы, — а вместо «Изменить поиск» у таблицы кнопка «Обновить». Так делают «Мои черновики»: рамка «Автор = Я» отбирает записи, искать нечего;
table — найденные: title, columns (свойства колонок), sorts и рамка — какие записи форма вообще видит и правит. Её задают фильтром теми же словами, что в запросе к базе, — ключом filter, или внутренним деревом filter_ast. Фильтр самого представления действует тоже: записи должны пройти оба. Таблица найденного обновляется сама, как вид базы: чужая правка, новая или удалённая запись появляются без повторного поиска;
edit — правка: title, description, submit_label, success_message, fields. Видимые поля показывают значения записи, умолчание подставляется только в пустое поле, скрытые пишут своё значение всегда.
Поля по-прежнему можно называть именем, ключом схемы или UUID; незнакомое имя — ошибка 400, а не молчаливый пропуск. В ответе поля записаны UUID свойств.
Пользователь
Формулы: синтаксис, операции и функции
Свойство типа «Формула» вычисляется по выражению, которое видит значения остальных свойств этой же записи. Значение пересчитывается при изменении записи и хранится вместе с ней, поэтому по формуле можно фильтровать и сортировать.
Где вводится формула
Откройте базу, нажмите на заголовок столбца и выберите «Изменить свойство» (или создайте новое свойство и укажите тип «Формула»). В форме появится поле «Выражение» и ссылка «Документация», которая ведёт именно на этот раздел. Выражение сохраняется вместе со свойством и применяется ко всем записям базы.
Ссылки на свойства
Свойство подставляется по названию — двумя равнозначными способами:
Название в ссылке должно совпадать с названием свойства. Если свойство переименовали, формулу нужно поправить: ссылка идёт по имени, а не по внутреннему идентификатору.
Типы значений
Число — число, результат арифметики, длина строки.
Строка — текст, название выбранной опции, отформатированная дата.
Да/Нет — true и false, результат сравнения.
Список — множественный выбор, связи, значения связанных записей.
Пусто — null. Пустое поле в арифметике считается нулём, в тексте — пустой строкой.
Неизвестное имя свойства, неизвестная функция, деление на ноль и незакрытая скобка останавливают вычисление — в ячейке появляется описание ошибки.
Формула видит только свойства своей записи. Значения связанных записей достаются свойствами «Поле связанной записи» и «Rollup», а формула уже считает по ним.
Формула не может ссылаться на саму себя и на другую формулу, которая ссылается на неё.
Пользователь
Доступ и совместная работа
Для страницы, папки и базы доступны уровни чтения, комментирования и редактирования. Право можно распространить на дочерние объекты.
Как раздаются права
Права на объект выдаются в окне «Доступ» (кнопка «Доступ» у страницы, папки или базы), блок «Соавторы». Кнопка «?» в заголовке этого блока открывает этот раздел документации отдельным окном. Раздавать права может автор объекта, а также владелец и администратор пространства — остальным соавторам кнопка «Доступ» показывает только то, что им доступно.
Уровней четыре, каждый включает возможности предыдущего:
Чтение — объект открывается только для просмотра.
Комментарии — к странице и к отдельным блокам можно писать комментарии, само содержимое не меняется.
Переписка — можно добавлять свои блоки и править или удалять только те, которые создали вы сами; чужие блоки остаются нетронутыми. Вложенные страницы, базы, папки, встроенные виды базы и синхронизированные блоки на этом уровне не создаются.
Галочка «Наследовать права дочерним объектам (дерево)» задаёт, действует ли право только на сам объект или на всё его дочернее дерево на любую глубину. Уровень и наследование у уже выданного права меняются в его строке в списке соавторов, там же право и отзывается. Выданное право человек видит в разделе «Доступное мне» над своим деревом.
Выдать право можно тремя способами: «Добавить» — выбранному человеку, которого вы нашли по имени или адресу (он уже есть в системе); «Пригласить» — одноразовой ссылкой, когда адрес неизвестен или человека в системе ещё нет (см. ниже); «Ссылка на страницу» — копирует внутренний адрес объекта, чтобы отправить его тому, кому право уже выдано. Сама внутренняя ссылка прав не даёт: открыв её без права, человек увидит отказ.
Одновременная правка
Несколько человек могут править одну страницу одновременно. Если пока вы печатали, страницу успел изменить кто-то другой, Vtorum сам сводит правки: чужие новые, изменённые и удалённые блоки приходят к вам, ваши — сохраняются поверх, новые блоки встают туда, куда вы их поставили. Если один и тот же блок правили оба, остаётся последняя правка, а предыдущая версия видна в истории блока. Блок, который удалили, пока вы его правили, возвращается с вашим текстом. Сообщений о конфликте при этом нет. Так же сходится и порядок записей в базе: если, пока вы перетаскивали строку, кто-то добавил или удалил запись, ваш порядок применяется, а новая запись встаёт рядом со своим соседом.
Абзац, в котором сейчас стоит курсор другого человека, подсвечен, под ним мелко написано «Редактирует …» с его именем, и править этот абзац, пока он в нём, нельзя — двое не печатают в один абзац одновременно. У каждого человека закрыт только один абзац — тот, где его курсор сейчас. Как только курсор уходит в другой абзац, прежний сразу освобождается; если человек переключился на другую вкладку или окно, освобождается и его абзац. Закрытая без выхода из текста вкладка отпускает абзац не позже чем через 20 секунд. Перезагрузка страницы в той же вкладке отпускает абзац сразу: свой же абзац из прошлой загрузки не показывается как занятый другим. Пометка «Редактирует …» с вашим именем появляется, только если абзац сейчас правится в другой вашей вкладке или окне.
«Доступное мне»: в своё дерево и отписка
Объекты других пространств, к которым вам выдали доступ, собраны в разделе «Доступное мне» над деревом. Объект можно перетащить оттуда в дерево своего пространства — в любую ветку, перед или после строки — или выбрать в меню «…» у объекта команду «Перенести в дерево» (встанет в конец корня). Объект остаётся чужим: открывается с тем же уровнем доступа, что вам выдали, а его ветка показывает только доступные вам дочерние объекты. Ссылка личная — её видите только вы; в «Доступное мне» объект больше отдельно не показывается. Внутрь чужого объекта свой или другой чужой объект положить нельзя.
В дереве такую ссылку переносят как обычную строку, а «Убрать отсюда» возвращает объект в «Доступное мне» — доступ при этом не меняется. Команда «Отписаться» (в меню «…» объекта в «Доступное мне» или в дереве) отказывается от доступа: ваше право на объект удаляется, он пропадает и из раздела, и из дерева, а владелец больше не видит вас среди соавторов. Вернуть доступ может только он — новым приглашением.
Как выбирается человек
Список пользователей платформы — персональные данные, поэтому целиком он не показывается никому. В поле выбора соавтора (и при добавлении участника пространства) сразу видны только те, кого вы и так видите: участники вашего пространства и ваши собственные системные учётные записи для API.
Любого другого человека можно найти, если вы его уже знаете: введите адрес электронной почты целиком или имя полностью. Поиск отвечает только на точное совпадение — по части имени или части адреса никто не находится, поэтому перебором каталог не собрать. Частота таких запросов ограничена.
Если человек найден по имени, его адрес показывается замаскированным (например, i***v@e***e.ru): этого хватает, чтобы различить полных тёзок, но сам адрес не раскрывается. При поиске по адресу он показан целиком — вы его и так знали.
Человек выбирается щелчком в списке найденных. Если адрес введён целиком и нашёлся ровно один человек, он выбирается сам; Enter выбирает единственного найденного. Пока никто не выбран, кнопка «Добавить» неактивна и подсказывает, что сначала нужно выбрать человека.
Под полем поиска в блоке «Соавторы» — три кнопки в ряд: «Добавить» (выбранного человека), «Пригласить» (одноразовая ссылка, см. ниже) и «Ссылка на страницу» (у базы — «Ссылка на базу», у папки — «Ссылка на папку»; на телефоне — коротко «Ссылка») — она копирует внутреннюю ссылку на объект, ту же, что пункт меню «…». Её и отправляют добавленному соавтору. Галочка «Наследовать права дочерним объектам (дерево)» под кнопками задаёт, действует ли новое право на всё дочернее дерево.
Приглашение по одноразовой ссылке
Когда имя и адрес неизвестны или человека ещё нет в системе, работает кнопка «Пригласить по ссылке» (в панели доступа к объекту — «Пригласить») — она есть и в панели доступа к объекту, и при добавлении участника пространства. Выберите уровень доступа (для объекта — при необходимости и наследование на дерево) или роль в пространстве и нажмите кнопку.
Главное в этой кнопке: приглашать можно человека, которого во Vtorum ещё нет, и заранее знать его адрес не нужно. Выбранный уровень доступа запоминается самой ссылкой. Получатель открывает её, проходит обычный вход или регистрацию — учётная запись создаётся тут же, — и сразу после этого ссылка отдаёт ему приготовленное право и открывает нужный объект. Повторно открывать ссылку или просить кого-то выдать права вручную не требуется.
Право создаётся сразу и появляется в списке как приглашение по ссылке: запись уже есть, но принадлежит пока не учётной записи, а ссылке.
Ссылка тут же копируется в буфер обмена, о чём панель сообщает — и подсказкой под формой, и всплывающим уведомлением «Ссылка-приглашение скопирована в буфер обмена». Показывается она один раз: на сервере хранится только её отпечаток, восстановить ссылку нельзя.
Отправьте ссылку любым способом — например, в мессенджере.
Когда получатель открывает ссылку, приглашение замещается правом его учётной записи, а приложение сразу открывает нужный объект. Если он ещё не вошёл, ссылка запоминается и срабатывает сразу после входа или регистрации.
Ссылка одноразовая и действует 7 дней: после первого открытия она больше не работает. Ожидающее приглашение можно отозвать в том же списке — например, если ссылка потерялась или ушла не тому человеку; тогда выпустите новую. Собственное приглашение принять нельзя.
Комментарии поддерживаются на уровне страницы и конкретного блока.
История страницы хранит крупные снимки, а история блока — точный аудит создания, изменения, перемещения, удаления и восстановления.
Открытый редактор и дерево получают изменения других пользователей без ручной перезагрузки.
Пользователи могут одновременно менять разные блоки. Для одновременного изменения одного блока действует optimistic locking с ответом 409 вместо молчаливой перезаписи.
Видеовстреча объекта
В окне чата объекта рядом с кнопкой «Открыть объект» (она открывает объект в новой вкладке, чтобы страницу не закрывало окно чата) есть кнопка «Видеовстреча». Она открывает окно на 90% экрана со звонком в Jitsi Meet (meet.vtorum.net); кнопка «Развернуть» в шапке окна переносит встречу на весь экран в соседнюю вкладку — входить в него отдельно не нужно: Vtorum сам подписывает короткий токен входа. Войти может любой, у кого есть доступ к переписке объекта (минимум чтение); комната одна на объект, поэтому все участники попадают в одну встречу. Окна подготовки нет: человек входит сразу под своим именем из Vtorum, с выключенными микрофоном и камерой. Протокол встречи (запись и расшифровка отдельной дочерней страницей) ведёт помощник Vtorum; его можно отключить выключателем «Вести протоколы встреч» в настройках «Функции AI → Протоколы встреч» (по умолчанию включено; настройка действует для встреч, которые начинает сам человек). Название встречи совпадает с названием объекта, а адрес комнаты состоит из названия латиницей и неугадываемого суффикса. Редактор объекта входит модератором.
Кнопка «Гостевая ссылка» в окне встречи копирует ссылку для участников без учётной записи Vtorum: она действует 24 часа, пускает только в комнату этого объекта, без прав модератора, и не открывает доступа к самому объекту. Создать её может тот, кто редактирует объект. Ссылка не хранится на сервере: подпись и срок записаны в ней самой, поэтому отозвать её раньше срока нельзя.
Для работы в настройках сервера задаются MEET_URL (адрес Jitsi, https), MEET_JWT_SECRET (тот же секрет, что JWT_APP_SECRET у Jitsi) и, при необходимости, MEET_JWT_APP_ID (по умолчанию vtorum). Без них кнопка отвечает, что видеовстречи не настроены. Если задан MEET_AGENT_URL, во встречу автоматически заходит бот Vtorum agent (служба tools/meet-agent рядом с Jitsi).
Vtorum agent: запись и расшифровка встречи
Бот заходит в комнату сам, как только кто-то начал встречу кнопкой в чате или открыл гостевую ссылку, и пишет только звук. В чат встречи он пишет, что запись идёт. Когда в комнате 45 секунд никого нет, бот выходит, и во Vtorum появляется дочерняя страница объекта «Встреча ДД.ММ.ГГ ЧЧ:ММ - ЧЧ:ММ» (московское время): в ней запись встречи одним звуковым файлом и расшифровка диалогом: когда начинает говорить новый человек, выделенной строкой «ЧЧ:ММ Имя:», под ней — абзацы с тире; реплики одного человека идут подряд в одном абзаце, а заметная пауза (больше пяти секунд) начинает новый абзац с тире.
Расшифровка идёт моделью AI того, кто начал встречу (Настройки → AI, модель расшифровки речи); если AI не подключён, страница всё равно создаётся с записью и пояснением. Страница создаётся от имени начавшего встречу: если у него нет права редактировать объект, она попадает в корень его пространства. Встречи короче двух минут без единой реплики страницу не создают.
Для API службы агента во Vtorum есть три служебных маршрута под /api/public/meet/agent/ (расшифровка реплики, загрузка записи, итог встречи): они открыты без входа, но принимают только подписанный токен встречи, который Vtorum выдаёт агенту при запуске, и ограничены по частоте.
Пользователь
Веб-публикации
Страницы, папки и базы можно публиковать без авторизации. Публичное представление повторяет режим чтения и не содержит управляющих элементов. Настройки публикации разложены по разделам (с 5.44.0): Доступность (дочернее дерево, свойства базы, поиск по базе), Навигация (панель слева, хлебные крошки, содержание), Внешний вид (название пространства, комментарии, транскрипция аудио в них) и Экспорт (PDF, «Скачать все файлы», «Взять себе» во Vtorum, индексация поисковыми сервисами). Настройка «Кнопка редактирования» (раздел «Внешний вид»): вошедшему во Vtorum читателю, у которого есть право правки этой страницы, в ряду круглых кнопок публикации добавляется карандаш — он открывает страницу в редакторе Vtorum. Остальным читателям кнопки нет. Если у пространства есть свой логотип, он стоит в шапке публикации вместо знака Vtorum, а участникам пространства логотип показывается в редакторе и в настройках (раньше показывался только его загрузившему). Окно комментариев в публикации всегда целиком помещается на экране: низ выше низа экрана, а если комментариев много, список внутри прокручивается. В публикации видны все комментарии — и читателей, и сделанные в редакторе; не показываются только те, обсуждение которых закрыто кнопкой «Закрыть обсуждение». Панель комментариев в редакторе закрывается кликом вне её. Виды базы данных, не помещающиеся в ширину (таблица, доска и др.), в редакторе имеют по краям кнопки «Прокрутить влево» и «Прокрутить вправо» — они плавно двигают вид на 80% его ширины и дублируют горизонтальный жест трекпада или мыши; кнопка видна только там, куда можно двигаться. В мобильной версии (узкий экран и сенсорный ввод) этих кнопок нет: вид уводят вбок пальцем. В хлебных крошках публикации перед названием корневого объекта стоит значок домика — он ведёт на главную страницу публикации. На узком экране (телефон) дерево публикации не стоит над страницей: круглая кнопка с тремя полосками слева открывает выдвижную панель с деревом, закрыть её можно кликом по затемнению или переходом на страницу. Панели публикации (дерево и страница) стоят рядом с отступом 24px и на широком экране центрируются вместе. Пункт «Содержание» с ссылкой «слева» / «сверху» (по клику ссылка меняется на другую) показывает список заголовков страницы над текстом («сверху») или отдельной панелью левее страницы («слева», на широком экране; при включённой панели навигации порядок такой: навигация, содержание, основной блок; на телефоне вместо панели содержание стоит над текстом), «Хлебные крошки сверху» — путём над заголовком, а «Навигация слева, порядок» — боковой панелью с деревом опубликованных объектов и фильтром по нему; первой строкой в ней всегда стоит корневой объект публикации со значком домика, как в хлебных крошках, и стоит левее дочерних объектов (без колонки под стрелку). Окно «Доступ» показывает только применимые настройки: «Публиковать свойства базы» и «Поиск по базе» — у базы данных или у объекта, в дереве которого (на любую глубину) есть база, при включённом «Публиковать дочернее дерево»; обе галочки содержания — если на странице есть заголовки H1–H4; «Панель навигации слева» и «Хлебные крошки сверху» — если опубликовано дочернее дерево и в нём есть объекты; транскрипция аудио — если включены комментарии. Порядок дочерних объектов в панели — ссылка рядом с галочкой «Навигация слева, порядок» (по клику «как в родителе» меняется на «по алфавиту» и обратно): «как в родителе» — в том порядке, в каком объекты расположены в родителе (как в дереве пространства), или «по алфавиту» — по возрастанию названий без учёта регистра, числа в названиях как числа («2.» раньше «10.»). Фильтр ищет по подстроке названия и понимает запрос, набранный не в той раскладке: «ryb» найдёт «Книги». Ветки с совпадениями раскрываются, найденные объекты отмечены янтарной полосой слева, а совпавший фрагмент названия подчёркнут — так найденное не спутать с открытой страницей, которая выделена бирюзовым фоном.
Доступ по паролю
Галочка «Доступ по паролю» под «Опубликовать» (с 5.44.0) закрывает публикацию паролем. При включении сервер создаёт случайный пароль — он виден в той же строке, только для чтения, рядом кнопка копирования. Читатель по ссылке видит окно ввода пароля; неверный пароль оставляет окно с подсказкой, верный открывает публикацию и запоминается в этом браузере на 30 дней. Снятая галочка стирает пароль, повторное включение выдаёт новый — так отзывают доступ у всех, кому пароль уже передан.
Пароль проверяет сервер, а не страница: без него не отдаются ни страницы, ни дерево, ни файлы, ни комментарии, ни PDF, Markdown и архив файлов публикации.
Превью ссылки в мессенджерах и поисковики видят только «Публикация защищена паролем» — без названия, описания и обложки; такая публикация не индексируется.
На ввод пароля — 10 попыток с одного адреса за 10 минут.
Выгрузки владельца из окна «Доступ» — PDF, MD и «Сайт» — пароля не спрашивают; в автономном сайте пароля нет.
Раздел «Сравнение»
На сайте notes.vtorum.net (с 5.50.0) есть отдельная страница «Сравнение» (/compare); ссылка на неё — пункт «Сравнение» верхнего меню главной, страница открывается в том же окне и с тем же меню. На ней схема, в центре которой знак Vtorum, а вокруг — знаки известных сервисов (Notion, Confluence, Obsidian, Google Документы, Evernote, OneNote). Нажатие на знак открывает страницу /compare/<сервис> — «Vtorum vs …»: где Vtorum выигрывает, таблица сравнения и инструкция по переезду. С неё можно вернуться на главную сравнения /compare по ссылке «Все сравнения». Страницы открыты для индексации и входят в карту сайта; меню главной и страницы сравнения одно и то же: «О продукте», «Сравнение», «Новости», «Документация».
Тексты и знаки лежат в packages/shared/src/landing-compare.ts — один набор данных для главной, страниц сравнения, текста для роботов и приветственной страницы.
Приветственная страница внутри Vtorum (с 5.50.11 — «Что такое Vtorum», раньше «Vtorum: первое знакомство») краткая: одна схема-картинка (/what-is-hub.svg) с возможностями и последовательностью изучения — Главная, Применение, Сравнение, Документация, Новости; на карточках последовательности лежат области-ссылки на страницы сайта. Тексты и ссылки — в packages/shared/src/landing-whatis.ts; схему перерисовывает npx tsx scripts/generate-whatis-hub.ts, страницу в базе — команда pnpm welcome:rewrite --what-is-publish --apply.
Сведения о чужих сервисах — общеизвестные и осторожные: они меняются, поэтому страницы сравнения сопровождает оговорка об ознакомительном характере.
Раздел «Применение»: пиктограммы и знаки программ
Страницы раздела «Применение» (/usecases, с 5.50.9) устроены графически, а не текстом: на схеме у каждого направления — своя пиктограмма, на странице направления — ряд знаков программ, которыми это обычно решают (например, Confluence, Notion и Obsidian для базы знаний), стрелка к знаку Vtorum, шаги карточками и короткие плитки возможностей. Полное описание направления раскрывается ссылкой «Подробнее о направлении».
Пиктограмма и набор программ задаются у направления в packages/shared/src/landing-usecases.ts(icon, tools); знаки лежат в packages/shared/src/landing-tools.ts — контуры Simple Icons (CC0); названия и знаки принадлежат их владельцам.
Картинки-схемы для приветственной страницы перерисовываются командой npx tsx scripts/generate-usecases-hub.ts: на них те же пиктограммы.
Страница «Новости»
В пространстве суперадмина есть системная страница «Новости» (с 5.47.0): на ней собраны ключевые доработки Vtorum от новых к старым. Каждая новость — дочерняя страница с датой и временем (московским), краткое описание видно в списке, полное открывается по клику на заголовок. Всё дерево опубликовано с индексацией поисковыми системами. Страница открывается без входа: на главной странице notes.vtorum.net в верхней полосе есть пункт«Новости», который ведёт на неё; вошедшим пользователям ссылка «Новости» есть и в левом меню настроек — сразу под «Документацией».
Новости лежат файлами в docs/news — формат и правила описаны в docs/news/README.md. Название новости — её ключ: менять его задним числом нельзя.
При переключении production на новую версию (и при выкатке сразу на prod) команда publish-news добавляет недостающие новости: заведённые раньше она не трогает, поэтому запуск повторяем. Сбой новостей предупреждает, но не откатывает выкатку.
Вручную: pnpm news:publish показывает, что будет добавлено, с флагом --apply — добавляет.
Выгрузка публикации — ряд кнопок под настройками (с 5.50.69 вместо прежнего меню «Скачать»): «PDF», «MD» (или MD архивом с деревом) и «Web» — автономная копия публикации ZIP-архивом с index.html, которую можно открыть без интернета или выложить на любой хостинг (подробно — в разделе «Импорт и экспорт»). Там же, рядом с адресом публикации, на устройствах с системным меню «Поделиться» стоят кнопки «Поделиться ссылкой» и «Поделиться PDF»: ссылка или готовый PDF уходят в другое приложение.
Публиковать можно и через API: PUT /v2/pages/{id}/publication с телом {"published": true}. Нужны права на изменение объекта (scope pages.write и доступ edit) — быть владельцем или администратором не требуется. В ответе приходит адрес публикации. GET той же ручки отдаёт текущее состояние, DELETE снимает публикацию, сохраняя её настройки.
Можно включить публикацию дочернего дерева.
Каждая дочерняя опубликованная страница имеет собственный постоянный URL; переходы поддерживают кнопки браузера «Назад» и «Вперёд».
Тему публикации можно задать ссылкой: ?theme=dark в конце адреса открывает её всегда в тёмной теме, ?theme=light — всегда в светлой, ?theme=auto возвращает тему читателя. Тема ставится до первого кадра, без вспышки, и действует на корневой и на всех дочерних страницах этой публикации: при переходах параметр остаётся в адресе, а во вкладке запоминается, так что держится и после перехода по обычной ссылке. Выбор темы самого читателя в остальном Vtorum не меняется.
Публикация не устанавливается как приложение Vtorum: «На экран Домой» или «Добавить на главный экран» на телефоне создаёт ярлык на саму публикацию с иконкой объекта, и он открывается в браузере сразу на ней, а не формой входа.
При отправке ссылки в Telegram и другие сервисы Vtorum формирует превью с названием, описанием и обложкой либо первым изображением страницы.
Галочка «Название пространства» управляет всем верхним брендовым блоком.
Breadcrumb содержит путь от корня до родителя, но не название текущего узла.
Записи опубликованной базы открываются из её представлений.
Если в виде не включён перенос текста (wrap_cells), связи и люди в ячейке идут одной строкой и обрезаются по ширине колонки — строка таблицы не растягивается от записи с десятками связей. Свойство, которого нет в раскладке колонок вида (property_layout), таблица показывает — служебные связи явно скрывайте (hidden: true).
В колонках-связях опубликованной таблицы видны названия связанных записей — даже если база этих записей не опубликована: колонку в опубликованный вид вывел автор. Скрытые колонки названий не получают. Открыть связанную запись можно, только если её база опубликована, — иначе название показывается без ссылки.
Склонение названий в упоминаниях
Что это, если коротко. Когда вы пишете «позвонил» и ставите ссылку на страницу «Андрей» (наберите «[[» в тексте и выберите страницу), ссылка вставляется названием страницы в именительном падеже: «позвонил Андрей». Читать так неудобно. Со склонением Vtorum сам меняет окончание по смыслу предложения: «позвонил Андрею», «это отец Андрея», «живёт в Москве». Ваш текст и название самой страницы при этом не меняются: склонение — это только то, как ссылка показывается в редакторе, в публикации и в выгрузках.
Маленькая буква. Если ссылка стоит в середине предложения и называется обычным словом («Мышление», «Творческое мышление»), оно показывается с маленькой буквы, даже когда падеж не меняется: «называется мышление». Имена, фамилии, города и начало предложения остаются с заглавной; не трогается и название после двоеточия или тире, где ссылка чаще служит именем объекта. Исключение — слово сразу после прилагательного («опустошённый Разум» → «опустошённый разум»): там это обычное существительное. Названия, которые обычно пишутся с заглавной («Бог», «Земля», «Волга», «Христос»), остаются с заглавной в любом падеже. Слово после прилагательного согласуется с ним в падеже («между действующим организмом»), а имя автора после слов «работа», «теория», «идея» и подобных ставится в родительный («благодаря работам Франциско Варелы»).
Две настройки страницы. Обе лежат в меню «…» страницы → «Настройки страницы».
«Склонение в упоминаниях» — главный выключатель. Включён у всех страниц, в том числе старых. Выключите, если пишете не по-русски или хотите видеть названия дословно: тогда ссылки везде показываются так, как названа страница.
«Кнопка настройки склонения у упоминаний» — показывает у каждой ссылки маленькую кнопку при наведении мыши. Нужна редко: склонение работает само. Включайте её, если склонение где-то ошиблось и нужно поправить одну конкретную ссылку. По умолчанию выключена и доступна только при включённом склонении.
Как поправить одну ссылку. Включите вторую настройку, наведите мышь на ссылку и нажмите появившуюся кнопку «Настройка склонения». В окне три варианта: «Не склонять это упоминание» (ссылка останется в именительном падеже), «Пол» (для имён, по которым пол не определить, например «Саша» или «Женя»; для остальных не нужен) и «Свой текст вместо склонения» (например, «Андрюши»). Выбор сохраняется вместе с текстом и действует и в публикации.
Название страницы в упоминании (ссылке на страницу прямо в тексте) в публикации склоняется по падежу, который программа определяет сама по словам рядом: страница «Андрей» в тексте «это отец Андрей» читателю показывается как «это отец Андрея», в «позвонил Андрей» — «позвонил Андрею», в «с Андрей» — «с Андреем». Падеж выбирать не нужно. В редакторе, в поиске и в боковой панели название остаётся как записано, а хранимый текст страницы не меняется.
Склонение действует во всех публикациях (с 5.44.0 отдельной галочки у публикации нет). Отказаться от него можно у конкретного упоминания: в его окне склонения есть отметка «Не склонять это упоминание» — такое упоминание показывается как записано. Отдельного выбора «пол имён по умолчанию» в настройках публикации нет (с 5.43.0): пол имени, которое по самому имени не определить («Саша», «Женя»), задаётся у самого упоминания, а без такого выбора имя склоняется как мужское. Публикации, где раньше был выбран женский пол, его сохраняют. Склонение действует в самой публикации, в её PDF и в Markdown-выгрузке публикации.
Падеж берётся из слов слева в том же предложении: предлог («у Андрея», «с Андреем», «о Андрее»), глагол («позвонил Андрею», «увидел Андрея»), слово родства или принадлежности («отец Андрея», «фото Андрея»), перечисление («у Андрея и Марии»). Название в начале предложения, пункта списка, ячейки и после двоеточия или тире остаётся как есть, как и приложение к званию («дядя Андрей»).
Полное имя (имя, отчество, фамилия) после слова, называющего человека («отец», «мать», «сын», «дочь», «дед»…), — приложение, а не принадлежность: падеж берётся у слова родства по всему предложению. «Отец Борис Иосифович Кокуш жил в Керчи» остаётся как написано, «у сына Константина Ефимовича», «от матери Деворы Хаимовны» склоняются, потому что падеж виден по слову или предлогу. Одно имя («отец Андрей») по-прежнему даёт «отец Андрея», а точка с запятой начинает новую часть предложения. Если род слова родства и имени не совпадает («мать Константин Ефимович Кокуш», «сестра Борис Иосифович»), это не приложение, а принадлежность: «мать Константина Ефимовича Кокуша».
Склоняются русские имена, отчества и фамилии из одного–трёх слов и города; скобки между частями имени и хвост после запятой, тире или цифр остаются без изменений: «Дора (Бегора) Хаимовна Кокуш, урожд. Мизрахи (1909–1968)» → «Доры (Бегора) Хаимовны Кокуш, урожд. Мизрахи (1909–1968)». Пол определяется по имени и отчеству; пол по умолчанию из настроек публикации берётся, только если по имени он не определился. Латиница, названия не по имени («Линия Кокуш (по отцу)») и несклоняемые фамилии («Мизрахи», «Пиастро») не меняются. Язык — только русский. Если падеж определить нельзя, название остаётся как записано: точность важнее охвата.
Склоняются и названия-слова из словаря русского языка: «Мышление», «Творческое мышление», «Теория игр», «Алгоритмы» — «контекстами мышления», «к творческому мышлению», «о теории игр». Такое название пишется как обычное слово предложения, с маленькой буквы. После существительного в косвенном падеже («контекстами», «процесса») и после отвлечённого существительного («способность», «изучение», «развитие») название становится родительным: «способность организма». Пояснение в скобках после названия («Организм (живая система)») остаётся как есть; после слов, называющих объект («страница», «тема», «слово»), и после слов, которые могут быть и именительными («стол», «процесс»), оно не меняется. Слова, которых нет в словаре (редкие термины), несклоняемые слова, латиница и названия с заглавными словами внутри остаются как записаны; слова, которые часто бывают именами («Вера», «Надежда»), склоняются как имена.
Поправить вручную можно у каждого упоминания: при наведении в редакторе появляется кнопка «Настройка склонения» (по умолчанию она скрыта и включается настройкой страницы «Кнопка настройки склонения у упоминаний» в окне «Настройки страницы»; видна, только если склонение включено). В её окне упоминание можно не склонять, подсказать пол или задать свой текст вместо склонения (до 200 знаков).
В редакторе название в чипе упоминания тоже показывается в падеже, как его увидит читатель публикации; сохранённый текст страницы и название самой страницы при этом не меняются, а при наведении на чип всплывает исходное название. Склонение в редакторе включено на всех страницах, в том числе старых. Отключить его для страницы можно пунктом «Склонение в упоминаниях» в окне «Настройки страницы» (меню «…»); ручные настройки упоминания («не склонять», пол, свой текст) учитываются и в редакторе.
В API это поля публикации inflect_mentions и inflect_default_gender, поле упоминания mention.page.inflection (skip, text, gender) и маршрут предпросмотра POST /v2/inflect-preview.
«Взять себе»: читатель уносит рабочую копию
Галочка «„Взять себе“ во Vtorum» (раздел «Экспорт») в Настройках доступа → Публикация добавляет на публикацию кнопку «Взять себе». По ней читатель получает копию объекта в своём пространстве и правит её как собственную: связи с оригиналом не остаётся, и дальнейшие правки автора до копии не доходят. Так раздают шаблоны и каталоги: методику, дневник, готовую базу с формой.
Копия ложится в папку «Входящие» — если пространств несколько, в текущее; пространство, где нет права создавать объекты, не предлагается. Незалогиненному читателю копировать некуда: намерение запоминается и применяется само сразу после входа или регистрации. Автор своей же публикации копию не получает — она легла бы рядом с оригиналом.
Что попадает в копию: сам объект и его дочерняя ветка, блоки страниц, базы вместе со свойствами, представлениями и формами, записи баз со значениями свойств, иконки и баннеры. Ссылки внутри взятой ветки переписываются на копии: упоминания страниц, встроенные виды и формы открывают базы копии, связи между базами ветки остаются связями внутри копии вместе с обратными полями, а rollup считает по своим свойствам. Поэтому встроенная форма на взятой странице создаёт записи в копии базы, а не в базе автора.
Ограничения. Ссылки за пределы взятой ветки не переносятся — связь с базой, которая в публикацию не входила, в копии пропадает. Вложения, картинки и баннеры остаются файлами автора: копия ссылается на них, и удаление публикации оставляет копию без этих файлов. Блоки «Личный сейф» не копируются. Если у публикации снята галочка «Публиковать дочернее дерево», читатель уносит только сам объект: отдавать копией дочерние страницы, которых он не видел, нельзя.
Интеграции
Импорт Buildin
В Настройки → Импорт → Buildin сохраняется API endpoint и токен. Импорт выполняется worker-ом и сохраняется после закрытия браузера. Задачу в статусе «Ожидает» или «Выполняется» можно отменить: worker остановится в безопасной контрольной точке, откатит текущую транзакцию и удалит созданные этой попыткой незавершённые S3-объекты.
Структурные блоки child_folder, child_database и child_data_source материализуются как папки и базы с сохранением вложенности. Предполагаемая папка остаётся папкой только тогда, когда её прямые блоки состоят исключительно из дочерних страниц, папок и баз; любой обычный блок превращает объект в страницу до materialization. Если Buildin возвращает дочерний блок во время обхода страницы-дедушки, импортёр сверяет его фактический parent.page_id, восстанавливает отсутствующую цепочку папок и не записывает потомка в тело дедушки. Для неоднозначного link_to_page один UUID проверяется как база и как страница; подтверждённая база имеет приоритет над page-фасадом. Если отдельная ссылка создаёт DAG-цикл или указывает на недоступного родителя, импортёр откатывает только эту связь до savepoint, записывает её в skipped_references и продолжает задачу. Если внешняя иконка недоступна, Vtorum использует стандартную пиктограмму вместо сломанного изображения.
Что импортируется
Страницы, папки, базы, записи, блоки, свойства, связи, иконки, баннеры и файлы. Неизвестный блок сохраняется как диагностический unsupported-блок, а не исчезает.
Устойчивость больших баз
Записи базы создаются пакетами с заранее распределёнными позициями. Worker обновляет прогресс по каждой записи, пишет heartbeat, проверяет отмену и ограничивает длительность SQL-операций. Ошибка materialization гарантированно переводит задачу в статус failed, поэтому импорт не остаётся бесконечно в состоянии «Выполняется».
Скорость открытия и сохранения страниц
Права на страницу, имя последнего редактора и время правки приходят вместе с содержимым: открытие больше не делает отдельных запросов за подписью и правами. Пути к родителям и проверки доступа, запрошенные одновременно, считаются один раз.
Второстепенное (признак «индексировать картинки», список заданий AI) загружается, когда браузер свободен. Список заданий обновляется по событию, а возврат в окно проверяет его не чаще раза в полминуты.
Сохранение пересчитывает связи страницы (упоминания, вложенные объекты) и список файлов только тогда, когда правка их затрагивает. Правка обычного текста не запускает пересчёт.
Публичные страницы, документация, формы и проверка подписи, а также окно настроек загружаются отдельными частями и не утяжеляют основное приложение.
Сохранение, которое заняло 250 мс и дольше, записывается в журнал сервера строкой «slow block save» с разбивкой по этапам (права, чтение страницы, запись блоков, пересчёт связей, триггеры, ответ). По этим строкам видно, на что уходит время, без догадок.
Порядок вложенных страниц в дереве пересчитывается только когда в тексте изменился их порядок или состав, а не при каждом сохранении страницы; нужные размещения читаются одним запросом.
Сохранение читает живые блоки страницы по индексу, а удалённые — только те, на которые ссылается запрос. У крупных страниц удалённых блоков тысячи, и чтение всех строк заставляло сканировать всю таблицу блоков: на странице в 180 блоков это занимало до 250 мс на каждое сохранение, теперь — несколько миллисекунд.
Пересборка связей страницы (упоминания и вложенные объекты) читает сведения о целях, существующие связи и запреты после переноса одним запросом на пересборку, а новые источники связей пишет одним запросом. Результат тот же, что и раньше, но время не растёт с числом упоминаний на странице.
Карточки базы с обложкой «первая картинка» получают превью изображений; для таблицы и остальных обложек превью не считаются.
Публикации с сотнями картинок
Ссылки на файлы публикации и страницы запрашиваются пакетами по 100 штук, по три пакета одновременно; картинки появляются по мере готовности каждого пакета. Раньше публикация с 385 картинками отправляла один пакет больше допустимых 200, получала отказ, и каждая картинка просила ссылку отдельным тяжёлым запросом — сервер вставал.
Пересжатие картинок в WebP для публикации идёт не больше чем в два потока одновременно, остальные ждут очереди; один и тот же файл, запрошенный несколькими запросами сразу, пересжимается один раз.
Если слепка картинки ещё нет, пакетная и одиночная выдача ссылок не ждёт его создания: первый посетитель сразу получает ссылку на оригинал, а слепок делается в фоне (очередь до 300 файлов). Следующие просмотры идут уже на лёгких WebP. Первый просмотр публикации с тысячами картинок поэтому быстрый, хотя картинки в нём тяжелее.
Поиск публикации по адресу и проверка «файл принадлежит публикации» запоминаются на 30 секунд (снятие публикации и блокировка вступают в силу не позднее), а число одновременных таких проверок ограничено. Ответ со ссылкой на файл браузер хранит пять минут.
Скорость правки ячеек
Числа, даты, выбор, флажки, ссылки и поля связи меняются в таблице сразу, не дожидаясь ответа сервера: после ответа запись заменяется серверной версией, а при отказе ячейка возвращается к прежнему значению и выводится причина. Форматированный текст, люди, файлы и вычисляемые поля показываются новыми после ответа. Названия связанных записей запрашиваются одним общим запросом на всю таблицу и хранятся полминуты, поэтому страница на сотни строк со связями не порождает сотни запросов.
Диагностика файлов
JSON-отчёт показывает исходный payload, найденный oss_name, кандидаты подписанных ссылок, HTTP-попытки, число байт, S3 key, PutObject и HeadObject. Прямой приватный CDN Buildin может отвечать 403; импортёр сначала ищет временную ссылку в доступных представлениях страницы.
Интеграции
Импорт и экспорт: Markdown, PDF, JSON, архивы
Объекты Vtorum выгружаются и загружаются несколькими способами. Дерево целиком — страница со всеми дочерними объектами — переносится через Markdown: выгрузка ZIP-архивом и импорт такого архива обратно. Остальные форматы выгружают одну страницу или один вид базы.
Что куда выгружается
Markdown, дерево целиком — кнопка «MD» в Настройках доступа → Публикация: один файл .md или ZIP-архив с дочерней веткой (подсказка кнопки тогда говорит «Скачать MD (архив)»). Подробно — ниже.
Сайт, публикация целиком — кнопка «Web» там же: ZIP-архив автономного сайта с index.html. Подробно — в разделе «Сайт: автономная копия публикации» ниже.
PDF, одна страница — кнопка «PDF» там же. Работает только у опубликованного объекта: сервер печатает его публичную версию, как её видит читатель, поэтому дочерние страницы в PDF не входят — их выгружают по одной. Читателям публикации ту же кнопку открывает галочка «Экспорт в PDF».
Markdown публикации без входа — у любой опубликованной страницы есть машинная версия /api/public/web/<адрес публикации>/export.md, для вложенной страницы публикации — с параметром ?node=<id>. Ссылки на картинки и файлы в ней рабочие, каждую можно скачать прямой ссылкой.
Все файлы страницы архивом — /api/public/web/<адрес публикации>/files.zip: вложения, картинки, видео, PDF и HTML страницы. Включается галочкой публикации «Кнопка „Скачать все файлы“»; без неё адрес отвечает отказом. Обе машинные версии объявлены в разметке публикации ссылками rel=alternate, поэтому агент, получивший обычную ссылку на публикацию, находит их сам.
Markdown через API — GET /v2/pages/{id}/content/markdown с токеном разработчика.
JSON вида базы — кнопка «Экспорт» в панели табличного вида. Включает публичную ссылку на JSON: массив записей с названием и значениями видимых полей этого вида, с его фильтрами и сортировкой, до 100 000 записей. Результат сужают параметры по названию поля, например ?Статус=Готово, — фильтры вида они не отменяют. «Новая ссылка» перевыпускает адрес, отключение закрывает его вместе с файлами записей. Ссылка публичная: по ней данные видны без входа во Vtorum.
Календарь — кнопка «Экспорт» в панели календарного вида: подписной календарь iCalendar для Google Calendar и Apple Calendar. Окончание события берётся из второго свойства-даты, если оно выбрано в настройках вида. Запись без времени начала выгружается на 9:00, а запись без окончания длится час.
Что откуда загружается
Markdown и ZIP в текущую страницу — меню блока или меню «+» → «Импорт MarkDown», до 5000 файлов за раз. Подробно — ниже.
Архив целиком с картинками — Настройки → Импорт: .md, .csv и ZIP, в том числе выгрузка Notion «Markdown & CSV» — хвосты-идентификаторы из имён её файлов убираются. Архив заметок Obsidian переносится со структурой каталогов, а его вики-ссылки становятся упоминаниями созданных страниц: [[Заметка]], [[Заметка|подпись]], [[Папка/Заметка#Раздел]] ведут на заметку, ![[картинка.png]] становится картинкой. Ссылка на заметку, которой нет в архиве, остаётся текстом; в блоках кода [[…]] не меняется. Дерево задают папки хранилища — ссылка не делает заметку дочерней. Содержимое складывается в отдельный раздел «Импорт · …».
Buildin по API — Настройки → Импорт → Buildin: страницы, папки, базы, записи, связи и файлы переносятся с сохранением вложенности. См. раздел «Импорт Buildin».
Markdown из буфера обмена — текст с разметкой Markdown, вставленный в блок, разбирается в блоки: заголовки, списки, цитаты, код, таблицы и оформление, а не ложится одним абзацем с решётками и звёздочками.
Папка с компьютера — перетащите её на страницу: каталоги станут папками Vtorum с той же вложенностью, файлы загрузятся в свои папки.
Markdown: как устроена выгрузка
Объект можно выгрузить в Markdown и вернуть такую выгрузку обратно. Формат построен так, чтобы архив читался любым редактором заметок: дерево выражено не каталогами, а обычными ссылками Markdown между файлами, которые лежат рядом.
Экспорт: где кнопка
Настройки доступа → Публикация → кнопка «MD». Что придёт, определяет галочка «Публиковать дочернее дерево»: со снятой уходит один файл .md с содержимым объекта, с поставленной — ZIP-архив с объектом и всей его дочерней веткой. Подсказка кнопки меняется вместе с галочкой («Скачать MD» или «Скачать MD (архив)»), поэтому результат виден до нажатия. Требуется право чтения объекта.
Сайт: автономная копия публикации
Настройки доступа → Публикация → «Web» (с 5.43.0, до 5.50.69 — пункт «Сайт» в меню «Скачать») собирает опубликованный объект в самостоятельный сайт и отдаёт его ZIP-архивом. Сервер открывает каждую страницу публикации так, как её видит читатель, и сохраняет готовую разметку вместе со стилями, шрифтами, скриптом, картинками, видео и файлами. В корне архива — index.html (корень публикации) и по HTML-файлу на каждую страницу, всё остальное — в папке assets.
Архив можно распаковать и открыть index.html двойным щелчком: сайт работает без интернета и без сервера Vtorum. Его же можно целиком выложить на любой статический хостинг (GitHub Pages, Netlify, S3, обычный веб-сервер).
Состав — как у публикации: при включённой галочке «Публиковать дочернее дерево» — все опубликованные страницы, папки, базы и записи баз, иначе — только сам объект (у базы — с её записями). В архив входит не больше 400 страниц; ссылки на остальные ведут на онлайн-версию публикации.
Вид повторяет публикацию: обложки, иконки, свои цвета страниц, навигация сверху и слева (дерево раскрывается и ищет по названиям), содержание страницы. Тема — по настройке системы читателя. Код в блоках копируется кнопкой «Копировать».
Чего в копии нет: комментариев, поиска по базе, «Взять себе», кнопок PDF и «Скачать все файлы» — им нужен сервер. Файл крупнее 200 МБ в архив не кладётся и остаётся ссылкой на публикацию.
Сборка идёт на сервере от нескольких секунд до нескольких минут — кнопка показывает ход: «Собираем сайт… 12 из 40». Требуются право чтения объекта и включённая публикация.
Что попадает в архив
Раскладка плоская, каталогов нет. Файлы названы по объектам, одинаковые названия расходятся как «Название (2)», разделители пути и служебные символы Windows из имён убираются.
Страница — файл с её блоками и ссылками на дочерние объекты.
Папка — тоже файл, содержимым которого служит список ссылок на вложенные объекты.
База — один файл-таблица: строка на запись, колонка на свойство. В ячейке названия стоит ссылка на файл записи, потому что содержимое записи в таблицу не влезает. Колонка названия всегда первая.
Запись базы — свой файл: её свойства и её страница.
Ограничения одной выгрузки: 2000 объектов и 10000 записей на базу — при превышении сервер отвечает ошибкой и предлагает выгрузить дерево частями.
Как переносится разметка
Заголовки, абзацы, маркированные и нумерованные списки, задачи, цитаты, выноски > [!NOTE], код в тройных кавычках с языком, формулы $, разделители, таблицы GFM с выравниванием, изображения и закладки. Из оформления текста переносятся жирный, курсив, зачёркнутый, моноширинный и ссылки; подчёркивание и цвет в Markdown выразить нечем, они остаются простым текстом. Вложенные пункты списка уходят на уровень глубже отступом.
Вложения в архив не копируются: изображения и файлы адресуются публичным адресом публикации, объекты вне выгрузки — адресом приложения, поэтому ссылок в никуда в файле не остаётся. Блоки «Личный сейф» чужого автора в выгрузку не попадают вовсе; свой отмечается строкой о том, что содержимое не экспортируется. Доска для рисования и mindmap отмечаются строкой — их содержимое в Markdown не переносится.
Служебные данные в файле
Точную структуру несёт front matter каждого файла: vtorum_id, vtorum_kind (page, folder, database, record), vtorum_parent и vtorum_order. Перечень дочерних объектов и список свойств записи помечены комментариями <!-- vtorum:children --> и <!-- vtorum:properties -->: человек их видит, а импорт вырезает, чтобы они не попали в содержимое объекта текстом.
Импорт: два пути
Меню блока или меню «+» → «Импорт MarkDown» — выбор файлов .md или ZIP-архива. Импортированные объекты становятся дочерними текущей страницы, а на месте вызова встают блоки-ссылки: только на объекты верхнего уровня, вложенные видны уже внутри них. Вложения этот путь не переносит, внешние ссылки на картинки остаются рабочими.
Настройки → Импорт — архив целиком, вместе с картинками. Содержимое складывается в отдельный раздел «Импорт · …», принимаются .md, .csv и ZIP.
Как импорт восстанавливает структуру
Три источника по убыванию точности:
метаданные выгрузки в front matter — папка остаётся папкой, таблица снова становится базой, запись возвращается в свою базу, порядок среди соседей сохраняется;
дерево каталогов архива — так импортируются прежние архивы с папками;
ссылки между файлами — файл, на который ссылается другой файл, становится его дочерним. Это работает и с чужим архивом Markdown, где метаданных Vtorum нет вовсе.
Ссылка на файл архива превращается в живую ссылку на созданный объект, а не остаётся нерабочей ссылкой на .md. Каталог главнее ссылок, поэтому старые архивы импортируются как раньше. Циклические ссылки импорт не роняют: спорный объект уходит в корень импорта.
У базы, собранной из таблицы Markdown, типы полей выводятся по значениям — как при импорте CSV. Формулы, связи и rollup при таком возврате становятся обычными полями, значения свойств берутся из таблицы базы, а содержимое записи — из её файла.
Интеграции
AI-функции
Каждый пользователь может подключить OpenAI-совместимый endpoint: OpenRouter, Polza.ai или собственный сервис. Настройки разделены по назначению.
Настройки → Подключение AI — endpoint, токен, пути API и диагностика списка моделей.
Настройки → Функции AI → Модели по умолчанию — минимальный общий набор: текст, summary, изображения, транскрибация и embeddings. Пустое поле конкретной функции наследует соответствующую модель по умолчанию во всех путях запуска: в ручном API, фоновой очереди и автоматической генерации баннера.
Настройки → Функции AI — необязательные переопределения цепочек и промптов для автозаголовков, саммари, баннеров и блока «AI-запрос». Галочка «Генерировать автоматически» есть только у баннера: она ставит задачу на баннер для заполненного объекта, у которого баннера ещё нет. Соотношение сторон и разрешение выбираются из значений, которые каталог провайдера допускает для выбранных графических моделей: провайдеры описывают у модели именно их, а размер в пикселях — нет. Значение из шапки блока «AI-запрос» важнее настройки функции, а модели, которая выбранного значения не знает, параметр не отправляется.
Настройки → Функции AI → Заметка — включение функции, транскрибация, саммари и автозаголовок.
Настройки → Функции AI → Пространство AI — Ассоциации на основе pgvector, монитор индекса и AI-ассистент для текущих пользователя и пространства.
Все поля выбора модели поддерживают поиск по подстроке идентификатора, названия и описания.
Интерфейс всех AI-разделов настроек использует увеличенный на 1 px кегль для более удобного чтения.
Токен хранится зашифрованным.
Импорт Buildin и обе AI-очереди обрабатываются независимо: долгий импорт не блокирует обращения к модели.
Задачи хранятся в PostgreSQL и восстанавливаются после перезапуска worker.
Заметка и AI-ассистент
После входа справа всегда отображаются две квадратные плавающие кнопки без текста. Режим «Заметка» является базовой функцией заметочника: он открывается при наличии прав редактирования и сохраняет текст, вложения и аудиозапись во «Входящих» даже без AI-подключения. Подключённые модели добавляют транскрибацию, перевод статьи, саммари, AI-заголовок и смысловые связи, но их отсутствие не мешает созданию исходной страницы. Без сети кнопка не помечается как ошибка AI и открывает упрощённый режим только для текста; заметка сохраняется в локальную очередь и синхронизируется после подключения. AI-ассистент по-прежнему требует настроенного AI и поиска источников. На мобильных touch-устройствах кнопки автоматически поднимаются над нижней панелью браузера, учитывают видимую область экрана и safe-area; некорректные промежуточные значения Android VisualViewport игнорируются. В режиме «Заметка» микрофон расположен рядом с кнопкой отправки; при нажатии приложение выполняет реальный запрос getUserMedia, поэтому браузеру остаётся показать стандартное окно разрешения. После изменения разрешения в настройках браузера старая ошибка очищается автоматически. При отказе интерфейс различает запрет политики сайта, iframe, браузера и системный запрет macOS.
Установленная через Chrome на Android PWA регистрируется системным получателем «Поделиться». Переданные текст, URL, изображения и файлы только заполняют окно «Заметка»; страница создаётся после явного нажатия «Отправить».
Изображения и файлы можно добавить вручную. Все изображения становятся первыми блоками страницы, первое изображение — баннером; остальные вложения создают файловые блоки.
Первая HTTPS-ссылка из текста безопасно раскрывается до конечного адреса. Vtorum извлекает заголовок, автора, description, preview и читаемую структуру статьи. Контейнеры рекомендаций, боковые новости, промоблоки и хвосты «Читайте также», «Новости по теме» и «Популярное» отсекаются по структуре и заголовкам после основного текста. Заголовок страницы берётся с сайта без AI, preview становится баннером, если пользователь не приложил изображение.
Исходная статья сохраняется структурированными блоками. Для нерусской статьи настроенная summary- или title-модель добавляет отдельный перевод на русский; без доступной модели оригинал всё равно сохраняется.
Для режима «Заметка» нужны права редактирования и включённая функция. AI-подключение и модели необязательны.
Без AI создаётся страница с исходным текстом, вложениями и/или аудиоблоком; транскрибация, перевод, саммари, AI-заголовок и смысловые связи пропускаются.
Для ассистента нужны проверенное подключение AI, текстовая модель ассистента, embedding-модель и путь embeddings API.
Статус заметки показан во вкладке Функции AI → Заметка, а embeddings и ассистента — во вкладке Функции AI → Пространство AI.
Диалог с ассистентом идёт в чате «Ассистент». Отправленный вопрос сразу появляется в окне чата и прокручивается в видимую область, ниже него крутится индикатор «Ассистент размышляет» с таймером ММ:СС, и ответ добавляется, когда модель его вернула. Сноски вида [1] в ответе и список «Источники» под ним — ссылки: клик открывает соответствующий объект. Окно чата разворачивается на весь экран кнопкой в шапке и сворачивается обратно.
В любом чате свои сообщения прижаты к правому краю и выделены фоном, сообщения ассистента и других участников — к левому краю на белом фоне. Пузырь сообщения по ширине текста и не шире окна; в своих сообщениях имя автора не показывается.
Параметры сохраняются для пары «пользователь + пространство», а endpoint и токен берутся из личного подключения AI.
Семантическая индексация и Ассоциации
Ассоциации постоянно включены для всех страниц и записей БД. Новая страница автоматически ставится на индексацию независимо от способа создания: через интерфейс, импорт, API, режим «Заметка» или фоновую операцию. При обновлении системы Ассоциации включаются и рассчитываются также для существующих страниц. Автоматические задания выполняются после успешного пробного запроса к актуальной embedding-модели; изменение endpoint, токена, модели, пути embeddings или размерности сбрасывает старую проверку. Размерность можно оставить равной 0 — она определяется по первому непустому вектору.
У записи базы данных в смысловой текст идут название, текст блоков, извлечённый текст вложений и блок «Свойства записи» — каждое непустое поле строкой «Поле: значение», у связей — названия связанных записей. Значения записываются так, как их читает человек: у поля «Пользователи» — имена людей, у формул и сводок — само значение без служебной обёртки (ошибка формулы в индекс не попадает), у файлов и галереи — имена файлов, у галочки — «Да» или «Нет». Изменение одного поля без правки текста тоже переиндексирует запись.
Ассоциации ненаправленные: если смысловая пара A—Б найдена при расчёте любой из страниц, она показывается у обеих. Результаты выводятся компактными чипами по убыванию коэффициента похожести; чем выше коэффициент, тем насыщеннее акцентный цвет чипа. Чип открывает объект его собственным адресом: страницу — /#/page/…, базу данных (например, базу, в которой лежит запись) — /#/database/…, папку — /#/folder/…; в ответе GET /api/pages/:id/connectivity у каждой ассоциации и родителя есть поле kind. Свежесть индекса определяется фактическим смысловым текстом и настройками embedding-модели. Служебные изменения размещения, revision или времени обновления не вызывают повторный provider call, если текст не изменился; worker только актуализирует source metadata.
Адаптер поддерживает числовые ответы, base64, base64_int8 и base64_binary, вложенные контейнеры result/output/response, поля vectors и values. Для pplx-embed-v1-* первым используется нативный base64_int8; binary декодируется LSB-first. Запрос автоматически перебирает варианты с/без dimensions и encoding_format, а при несовместимом batch повторяется по одному тексту. Для ненормализованных INT8-векторов поиск выполняется по cosine distance pgvector.
Монитор показывает проиндексированные, пустые, ожидающие, выполняющиеся, ошибочные, устаревшие и ещё не запускавшиеся страницы.
Для записей базы учитываются заголовок, свойства шапки, relations и текстовые блоки.
Ошибочные страницы можно повторить все вместе или по одной из монитора.
Раздел «Ассоциации» всегда расположен после редактора и не перемещается при добавлении, удалении или перестановке блоков.
В offline-режиме раздел скрывается и не выводит ошибку недоступности сервера.
Раздел меняется тихо: область списка имеет фиксированную высоту с внутренней прокруткой, поэтому пересчёт ассоциаций во время набора текста не сдвигает редактор и не заставляет страницу «прыгать».
В начале списка стоят страницы, которые ссылаются на эту: папки и страницы, где она размещена, и страницы, где она упомянута в тексте. У них связь 100 % — она записана явно, а не угадана по смыслу. Остальные чипы — смысловые ассоциации с процентом похожести; страница, которая есть среди ссылающихся, второй раз не повторяется.
Блок «AI-запрос»
Добавьте блок через меню «+» и выберите тип ответа: текст, картинки или аудио / транскрибация.
Введите запрос и при необходимости прикрепите до 20 файлов общим размером до 150 МБ.
Нажмите «Отправить» или Cmd/Ctrl+Enter.
Под композитором появится снимок отправленного запроса, затем worker добавит ответ отдельными блоками.
У типа ответа «Картинки» в строке с типом стоят кадр (соотношение сторон) и размер (разрешение). Значения не зашиты в Vtorum: они берутся из каталога провайдера для выбранных графических моделей — одна модель умеет три соотношения, другая полтора десятка, а разрешение описано классами 1K, 2K и 4K. «Из настроек» означает значение из Настройки → Функции AI → AI-запрос. Модели, которая выбранного значения не знает, параметр не отправляется, а цепочка запасных моделей начинается с тех, кто его поддерживает. Если модель разрешение вовсе не принимает — как openai/gpt-5-image, — поле остаётся на месте со значением «Не выбирается». Запрос с выбранным кадром уходит тем путём провайдера, который эти параметры принимает (генерация медиа), а не OpenAI-совместимым: тот знает только размер в пикселях и возвращал бы квадрат.
Текстовые файлы читаются напрямую (до 20 МБ на файл), изображения до 10 МБ передаются мультимодальной модели; остальные бинарные форматы передаются как метаданные. Для транскрибации сверху вставляется краткое саммари, затем заголовок «Полная транскрибация» и весь распознанный текст. Повторная отправка из того же блока продолжает диалог: контекст собирается из предыдущих запросов и ответов с тем же conversation_id, а при превышении лимита сворачивается моделью суммаризации.
Если reasoning-модель завершила ответ без финального message.content, клиент один раз повторяет запрос с явным требованием вернуть итоговый ответ. Внутренний reasoning не принимается за результат и не сохраняется в журнале ошибок.
Закрывать страницу во время обработки можно: запрос выполняется независимо от открытого редактора, а готовые блоки появятся автоматически после синхронизации.
Интеграции
Процессы: шаги, код и API
Во вкладке Настройки → Процессы собирается конвейер шагов «взять → обработать → положить». Запускается вручную из меню объекта или действием триггера «Запустить процесс». Исполняет всегда worker, по снимку определения: правка процесса не ломает уже идущие запуски.
Обработка кодом
В «Обработать» кроме шаблона текста и ИИ доступен Код (Node.js). Код пишется телом функции и возвращает результат через return. Доступны:
input — текст входа, то же, что видит шаблон в {input};
data — структура источника: у интегральных источников это запись, значения свойства или таблица целиком;
steps — результаты прошлых шагов по их ключам: { text, data };
console.log — строки попадают в журнал шага (output.logs в GET /v2/pipeline-runs/:id), в том числе у упавшего шага: там они рядом с текстом ошибки. Кнопка «Проверить» и POST /v2/pipelines/code/test тоже возвращают их при ошибке.
Строка, число или логическое значение уходят в «положить» как есть. Объект или массив сохраняются дважды: текстом (JSON) — для «положить» и журнала, и структурой — следующему шагу с кодом, чтобы его не пришлось разбирать обратно.
Коду доступны только вычисления: ни сети, ни файлов, ни require, ни доступа к процессу. Исполнение синхронное с пределом 2 секунды (максимум 10). Наружу данные отправляет приёмник «В webhook», а не код. Создавать и править шаг с кодом может владелец или администратор пространства — остальные шаги остаются за редактором.
Последний блок страницы
Источник «Последний блок страницы типа» берёт последний блок выбранного типа — абзац, выноску, файл, картинку, PDF, схему Mermaid и так далее — и отдаёт его текст; у вложений, где своего текста нет, — подпись или имя файла. Если блока такого типа на странице нет, источник отдаёт пустую строку, а не роняет запуск, поэтому им можно проверять условием «появилась ли расшифровка». Этот источник текстовый, и условию он операнд.
Интегральные источники
Кроме заголовка, текста страницы и одного свойства шаг умеет брать данные целиком:
Вся запись базы — заголовок и значения всех свойств, по именам и по идентификаторам, плюс схема базы;
Все значения свойства — массив «запись → значение» по всей базе;
Вся таблица базы — строки со значениями всех свойств. Базу можно выбрать любую в пространстве, она не обязана быть связана с предметом запуска; если базу не указать, берётся база самого предмета. Именно это даёт «сумматор»: процесс висит на записи-итоге в одной базе, берёт источником всю таблицу другой, считает по ней кодом и кладёт результат в своё свойство.
Выборка ограничена 5000 строками; если строк больше, в ответе стоит truncated: true. Условиям такие источники не операнд — сравнивать таблицу целиком не с чем; поставьте перед условием шаг с кодом.
Как выглядят значения в строках. Связь — массив идентификаторов связанных записей по порядку: "Юнит": ["6cfab232-…"], "Слагаемые": ["…", "…"]; «Пользователь» — массив идентификаторов пользователей; выбор — { "name": "…" }; дата — { "start": "…" }. В строках таблицы пустые значения опущены, пустая связь тоже: отсутствующий ключ читайте как пустое значение. У «всей записи» свойства перечислены все — пустое значение там null, пустая связь — []. Источник «одно свойство» у связи отдаёт тот же массив идентификаторов.
Куда шаг кладёт результат
«Положить» — такой же выбор из каталога, как «взять» и «обработать». Доступны:
variable — оставить переменной: результат никуда не пишется, его берёт следующий шаг через источник «Результат шага выше»;
property — в свойство предмета запуска: той самой записи, над которой идёт процесс (нужен property_id). В другую запись шаг не пишет — ни в связанную, ни в найденную источником. От этого зависит вся сборка автоматизации: чтобы посчитать по одной базе и записать в другую, процесс вешают на ту запись, куда нужно положить результат, а чужую базу берут источником. Значение приводится к типу свойства: число, которое вернул код, ложится числом, флажок — логическим значением; выбор и статус — вариантом из настроек свойства (код возвращает имя "Проведена" или объект { name } / { id }), множественный выбор — массивом таких вариантов; дата — { start } из строки "2027-03-22" или объекта; пользователь и связь — массивом идентификаторов. Неизвестный вариант, дата, которая не читается, и текст в числовом свойстве не записываются — шаг падает с понятной ошибкой. После записи пересчитываются формулы, rollup и поля связанной записи — как при правке руками;
block_append — абзацем в конец страницы; title — в заголовок;
email_self — письмом себе; email_other — письмом на адрес в recipient_email;
webhook — POST на url с тем же разбором адреса, что у действий триггеров;
ai_function — запустить готовую функцию над объектом: page_summary или banner_generation;
records_create — создать записи в базе database_id. Шаг возвращает массив объектов { title, properties }, и из каждого получается запись. Свойства называют именем, ключом схемы или id; значения приводятся к типу свойства теми же правилами, что у property (число — числом, выбор — вариантом, связь — массивом id, дата — строкой "2027-10-01"). До 1000 записей за шаг.
records_lock — заблокировать записи (жёсткое закрытие периода). Шаг возвращает массив id записей любых баз пространства — строкой или объектом { id }. До 5000 записей за шаг, всё или ничего: ошибка называет номер строки. Процесс блокирует только те записи, которые владелец запуска вправе править. "locked": false снимает блокировку — это доступно, только если владелец запуска — владелец или администратор пространства. Выход шага — { ids, locked, skipped } (skipped — записи, уже бывшие в этом состоянии). Смена блокировки события «изменение» не порождает и оставляет след в журнале (кто, когда, каким процессом).
context_command — контекстная команда блока: та же команда, что в контекстном меню блока («Транскрибация», «Описать», «Сделать summary», «Озвучить», «Иллюстрировать», «Создать карту смыслов»). В шаге выбираются тип блока и команда, характерная для этого типа; процесс находит последний блок этого типа на странице и запускает над ним команду. Под блоком сразу появляется заглушка с журналом действий, а по готовности её заменяет результат — ровно как при запуске из меню. Результат шага в команду не передаётся: она работает с самим блоком. Если блока такого типа на странице нет или команда ему не подходит, шаг падает без повторов.
Заблокированная запись
В шапке заблокированной страницы, записи или базы вместо кнопки «Доступ» стоит кнопка с замком: тот, кто вправе править объект, снимает ею блокировку. Настройки доступа при блокировке не меняются, поэтому кнопки «Доступ» у такого объекта нет; если окно доступа всё же открыто, в нём одно сообщение о блокировке и, если объект опубликован, его адрес. Свойства заблокированной записи показываются как обычно, связи — названиями связанных записей, по которым можно перейти.
Заблокированную запись не меняет и не удаляет никто: ни таблица (правка ячейки, массовые действия, вставка, перенос в корзину), ни карточка, ни форма, ни API (ответ 423), ни процесс — шаг записи в неё падает сразу, без повторов. Новые записи со связью на заблокированную (например, сторно) создаются как обычно, а вычисляемое у заблокированной записи продолжает обновляться: обратные связи, поля связанной записи, формулы и rollup. Блокировку, поставленную процессом, снимает только владелец или администратор пространства; блокировку, поставленную человеком, — любой, кто вправе править запись. Через API блокировку записи снимает запрос PATCH /v2/pages/{id} с телом {"locked": false} — без других полей.
Создание записей: правила пакета
Всё или ничего. Записи создаются в одной транзакции: ошибка любой строки отменяет весь шаг, а в сообщении — её номер: «Строка 12 — неизвестное свойство «Сума»». Половина проводок за месяц хуже, чем ни одной: повтор после исправления создал бы вторую половину поверх первой.
Идемпотентность. Необязательный upsert_key — имя, ключ или id свойства-ключа. Если в базе уже есть запись с тем же значением ключа, она обновляется, а не создаётся заново. Повторный запуск за тот же месяц проводки не задваивает: ключ вида «шаблон-2027-10» у каждой проводки свой.
Выход шага — { ids, created, updated }: все id по порядку строк, созданные и обновлённые. Следующий шаг кодом берёт их из steps.<ключ>.data — например, чтобы отметить в шаблоне последний проведённый месяц.
События. Созданная запись объявляется событием «создание», обновлённая — «изменение», с глубиной каскада, как любая правка процесса: дальше срабатывают разноска, факт, итоги и витрины.
Автор записей — тот, от чьего имени идёт запуск: создатель правила триггера или человек, запустивший процесс вручную. Это видно в поле «Автор».
Часовой предел (pipelineHourlyLimit) считается на пару «процесс + предмет». Каждая созданная запись — отдельный предмет, поэтому 1000 проводок за раз не упираются в предел разноски: у каждой свой счётчик.
Запуск по расписанию
Процесс запускают по часам триггером с объектом «время» (раздел «Триггеры»). В контексте прогона (/v2/pipeline-runs) и в коде шага — объект run: run.event_type (daily, weekly, monthly), run.scheduled_for — плановое время запуска и run.schedule — само расписание. Месяц определяют по scheduled_for: запуск, опоздавший из-за простоя, всё равно относится к своему 1-му числу. Пропущенный срок исполняется один раз после восстановления. Перезапустить месяц вручную — POST /v2/nodes/{id}/run-pipeline или кнопка запуска процесса в интерфейсе.
Когда страницу объявляют шаблоном и внутри неё есть вложенные объекты, Vtorum спрашивает, что переносить: только эту страницу, всё дерево или всё дерево вместе с записями баз. Второй и третий варианты и есть меташаблон — им повторяют не документ, а устройство: десяток баз, связи между ними, правила и расчёты. Такой шаблон можно сделать глобальным и отдать другому пространству одним действием. Вопрос задаётся, даже если ветка страницы в дереве слева свёрнута. Если страница уже стала шаблоном «только этой страницы», а нужна вся ветка, снимите с неё отметку «Шаблон» и объявите заново, выбрав «всё дерево».
Блоки-ссылки в перенесённой ветке ведут на объекты копии и открывают их сразу, даже пока ветка не раскрыта в дереве слева: ссылка на базу открывает базу, а не пустую страницу. Размещения объектов в копии свои — удаление блока-ссылки в копии не трогает шаблон.
Что переносится вместе с деревом:
страницы, папки и базы на любой глубине вложенности;
содержимое дочерних страниц — их блоки, включая картинки: страницы приходят заполненными, а не пустыми;
схемы баз: свойства с их настройками и все виды целиком — фильтры, сортировки, группировка, порядок колонок и формы со всеми их полями;
связи между базами — свойство-связь, смотревшее на базу шаблона, в копии смотрит на новую базу, а не на исходную; то же с rollup и связанными свойствами, даже когда они указывают на базу, скопированную позже;
ссылки внутри содержимого: блок-ссылка на страницу дерева и встроенный вид базы в копии ведут на копии, а не в пространство автора;
триггеры, настроенные на объекты дерева, и процессы, которые они запускают: внутри определения процесса переписываются идентификаторы свойств и баз.
Записи баз не переносятся по умолчанию. Обычно новые базы создаются пустыми: иначе в чужое пространство уехали бы боевые данные автора. Но бывают шаблоны, где записи и есть содержание, — каталог методик без единого примера превращается в набор пустых таблиц. Для них при объявлении шаблона выбирают «Всё дерево вместе с записями баз»: тогда переносятся и записи, и связи между ними — запись «Люди» в копии указывает на копию дневника, а не на дневник автора. Решение принимает автор шаблона один раз, тот, кто шаблон применяет, его не меняет.
Границу задаёт дерево — связь, ведущая за его пределы, при переносе отбрасывается: на той стороне ей не на что указывать. Получатель правила увидит их от своего имени; получатель сообщения в триггере заменяется на того, кто применил шаблон, — человека из чужого пространства в копии нет.
Копия редактируема. Обычный шаблон запирает блоки — копия документа должна остаться копией. Меташаблон не запирает ничего: ветку берут, чтобы ею работать, и заголовок каталога в своей копии правят как обычный текст.
Глобальные шаблоны
Шаблон живёт в своём пространстве, но его можно открыть остальным. Суперадминистратор или модератор шаблонов объявляет страницу глобальной — после этого она доступна на чтение всем, включая вложенные страницы меташаблона: прежде чем брать ветку, её можно посмотреть.
Базы данных ветки и их записи открыты всем, только если у меташаблона включено «переносить записи»: тогда записи — часть шаблона. Без этой галочки записи остаются данными автора: посторонний не видит ни сами базы ветки, ни их записи — ни по ссылке, ни через копию шаблона. Применить такой шаблон можно как раньше: базы копируются со схемой, видами и связями, но без записей.
Доступность и привязка — разные вещи. Глобальный шаблон видно по ссылке, а в списке шаблонов пространства он появляется только после привязки: иначе в окне выбора шаблона у каждого копился бы чужой набор. Пространство привязывает шаблон себе кнопкой «+» во вкладке «Шаблоны», а «Привязать всем» ставит привязку сразу всем пространствам — и тем, которые создадут потом: новое пространство получает шаблон в списке с первого дня, руками привязывать его не нужно. Кнопка — переключатель: включённая, она подсвечена и показывает значок с галочкой («Привязан ко всем»); повторное нажатие после подтверждения отвязывает шаблон от всех пространств, кроме его собственного, и от будущих тоже. Если шаблон перестают быть глобальным, снимаются и привязки, и это обещание. То же происходит, когда со страницы или базы снимают статус шаблона: глобальность, привязки к пространствам и привязка будущим пространствам уходят вместе с ним, и при повторном объявлении шаблон снова начинает как локальный.
В Настройки → Шаблоны у каждого значка есть подсказка при наведении, а на телефоне рядом со значком стоит подпись. Значок слева — вид шаблона (страница или база данных); кружок с глобусом в углу означает глобальный шаблон. Действия справа: «Привязать всем», «Сделать глобальным» / «Сделать локальным», «Удалить» (объект-шаблон уходит в корзину) и у чужих шаблонов — «Отвязать».
Отдельного действия у меташаблона нет. Его применяют тем же «Применить шаблон» из галереи: корень ложится на текущую страницу — её содержимое приходит из шаблона обычным путём, — а дерево вложенных объектов вырастает под ней. С точки зрения человека меташаблон ничем не отличается от шаблона, просто вместе со страницей он приносит устройство.
Применение идёт целиком: если что-то не удалось создать, не создаётся ничего. Дерево с половиной баз или со связями в никуда хуже, чем несостоявшееся применение.
Каскад процессов и защита от колец
Правка, сделанная процессом, порождает событие наравне с правкой человека: записанное в свойство даёт «изменение поля», записанное в заголовок — «изменение заголовка», и оба, как обычно, будят правило «изменение связанной записи» у тех, кто ссылается. Это и есть каскад: процесс считает строку бюджета, правило у проводки видит изменение, следующий процесс пересчитывает её — разные процессы правят разные базы по цепочке.
Так же будит правила правка через Developer API — от интеграции, импорта или агента. Создание страницы или записи (POST /v2/pages) даёт «создание», правка записи (PATCH /v2/pages) — «изменение», «изменение заголовка» и «изменение поля» по каждому полю, значение которого действительно поменялось (формулы и rollup — следствие, а не правка, и событий не дают), правка содержимого блоками — «изменение», удаление и перенос в корзину — «удаление». Все они будят и «изменение связанной записи» у тех, кто ссылается. Правило не различает, кто внёс правку.
Кольцо в плотной сети связей возникает по построению, а не по недосмотру, поэтому цепочка имеет предел длины. Глубина считается от правки человека: она нулевая, каждый следующий процесс добавляет единицу. На шестом шаге цепочка обрывается — событие не создаётся, а в журнале воркера остаётся запись о том, что каскад достиг предела.
Кроме предела глубины кольцо сдерживают ещё два ограничителя:
галочка процесса «Не запускать повторно из-за собственных изменений» — запуск не создаётся, если этот же процесс завершился над этим же предметом менее двух минут назад. Её стоит включать всюду, где процесс пишет в ту же запись, по которой настроено его событие;
часовой предел запусков на предмет — сто по умолчанию, настраивается в самом правиле от 1 до 1000. Он страхует от шторма, если кольцо всё-таки разошлось по настройкам.
В событии, порождённом процессом, лежит метка происхождения: идентификаторы запуска и шаблона и глубина каскада. По ней в журнале видно, чья правка вызвала цепочку.
Пределы запуска и работы
Процесс не запускается, если сработал любой из ограничителей:
сто запусков в час на пару «процесс + предмет» — настраивается в правиле от 1 до 1000;
затишье 120 секунд перед стартом: новое событие по тому же предмету сдвигает срок, поэтому серия правок даёт один пересчёт. Настраивается от 0 до 86 400 секунд (pipelineQuietSeconds). Нужен быстрый отклик — ставьте 5–10 с; данные приходят пачками — 30–60 с склеят пачку в один пересчёт;
склейка правок в редакторе — только для событий «создание», «изменение» и «изменение заголовка» от человека: доставка ждёт, пока объект закроют или правки прекратятся на 5 минут, иначе правило получало бы недописанный текст. Правка через API, сохранение формы и правка процессом — законченное действие, их событие уходит через секунду. «Изменение поля» и «изменение связанной записи» доставляются сразу. Итого после правки через API или формы процесс стартует примерно через 1–3 с + затишье правила;
изменение — только по смыслу: событие «изменение поля» создаётся, если значение действительно поменялось. Тот же вариант выбора или статуса в другой записи ({name} вместо {id, name, color}), тот же набор связей, людей или вариантов множественного выбора в другом порядке — не изменение. Это касается правок в интерфейсе, через API и записи процессом: процесс, записавший в поле то же значение, не будит правило на себя. Запись того же заголовка процессом пропускается;
параллельное исполнение: воркер ведёт несколько запусков одновременно (на сервере — три отдельных контейнера pipeline-worker, по ядру на каждый, в каждом по 4 запуска; переменные WORKER_ROLE и PIPELINE_CONCURRENCY), поэтому веер расчётов одного пользователя не задерживает остальных, а каскад из 5–6 процессов отрабатывает за секунды. Запуски над одной и той же записью идут строго друг за другом — два расчёта одной записи не перезапишут результат друг друга;
один активный запуск одного процесса над одним предметом: пока он идёт или ждёт в очереди, второй не создаётся;
глубина каскада — пять звеньев от правки человека;
галочка «не запускать повторно из-за собственных изменений»: две минуты после того, как процесс отработал над этим предметом.
Пределы самой работы:
пять попыток при сбое, пауза растёт с 30 секунд до 15 минут; ошибки, которые сами не пройдут (нет свойства, беда в коде, удалён предмет), не повторяются вовсе;
не больше 50 шагов в процессе;
код шага: до 20 000 символов, 2 секунды по умолчанию и 10 максимум, результат до 200 000 символов;
интегральные источники отдают до 5000 строк, дальше в ответе стоит truncated: true.
API процессов и триггеров
Все маршруты работают в текущем пространстве и требуют роли в нём.
Токен системного пользователя ходит только в Developer API V2, поэтому адреса автоматизации — под /v2/: /v2/pipelines, /v2/triggers, /v2/pipeline-runs, /v2/nodes/:id/run-pipeline. Интерфейс обращается к тем же обработчикам под /api/; устройство запросов и ответов у обоих адресов одно. Запуск процесса и чтение прогонов токеном требуют, кроме права на объект, ещё и скоупа automation.write / automation.read.
Системному пользователю (агенту с токеном) роль в пространстве не выдаётся — он не человек и в списке участников ему не место. Чтобы он мог собрать работающую систему целиком — базы, связи, процессы с кодом и правила, — токену выдают скоуп automation.write (или automation.read только для чтения). Право настраивать автоматизацию отделено от права читать и писать данные намеренно: это другая по смыслу власть — не «прочитать и записать», а «настроить, что случится само».
Больше прав, чем есть у человека, агент при этом не получает: при проверке берётся роль владельца токена — того, кто завёл системного пользователя. Владелец потерял доступ к пространству — теряет и агент. Шаг с кодом ему, как и человеку, доступен только при роли владельца или администратора.
Так же наследуется и подключение AI: своих настроек ИИ у системного пользователя нет и задать их негде, поэтому ИИ-шаг процесса исполняется на AI-оркестраторе и моделях владельца токена, и расход идёт с его подключения. Значит процесс с шагом fn: "ai" и триггер на него, созданные токеном, отработают при событии — при условии, что подключение AI есть у владельца. Если его нет ни у владельца, ни у агента, запуск отказывает сразу и без повторов: пять одинаковых попыток ничего бы не изменили.
GET /v2/pipelines — список процессов и свойства баз для выбора источников; GET /v2/pipelines/:id — один процесс с определением.
POST /v2/pipelines, PATCH /v2/pipelines/:id, DELETE /v2/pipelines/:id — создание, правка и удаление. Тело: name, description, definition, enabled. Определение с шагом-кодом требует роли администратора.
POST /v2/pipelines/code/test — прогон кода на пробных данных без записи: { code, input?, data?, steps?, timeout_ms? }. Отвечает { ok, text, data, logs } либо { ok: false, error }.
POST /v2/nodes/:id/run-pipeline — ручной запуск над объектом; GET /v2/nodes/:id/pipeline-runs и POST /v2/pipeline-runs/:id/cancel — отменить запуск: стоящий в очереди не начнётся, идущий остановится перед следующим шагом, сделанные шаги не откатываются. Выключение процесса (enabled: false) отменяет и все его запуски в очереди, в ответе — их число cancelled_runs. Воркер берётся за запуск не больше max_attempts (5) раз, число видно в прогоне.
GET /v2/pipeline-runs/:id — запуски и журнал шагов. Журнал хранит первые 20 000 символов входа шага; если вход длиннее, рядом стоят text_length и truncated: true. Сам шаг получает вход целиком — усечена только запись.
GET /v2/triggers, POST /v2/triggers, PATCH /v2/triggers/:id, DELETE /v2/triggers/:id — правила. Процесс привязывается действием run_pipeline и полем pipelineTemplateId; правка меняет enabled, привязанный процесс, предикаты значений, затишье и часовой предел. Событие linked_record_changed требует propertyId — поле связи, за которым следят. Адресат и событие не меняются — это другой триггер, его создают заново.
Тело правила принимается и в camelCase, и в snake_case — в том виде, в каком его отдаёт GET /v2/triggers, его можно отправить обратно:
У property_changed и linked_record_changed поле обязательно; у второго это должна быть связь. Предикаты значений (pipelineOldPredicate, pipelineNewPredicate) пока применимы только к property_changed.
Интеграции
Триггеры и автоматические действия
Во вкладке Настройки → Триггеры правило связывает объект, событие и действие. Объектом может быть ветка DAG от выбранной страницы или все записи выбранной базы. Доступны уведомления по e-mail, webhook, автоматическое создание клона и системное сообщение выбранному активному пользователю пространства.
Объект «время»: запуск по расписанию
Объект «Время (расписание)» — внутренний планировщик. Правило срабатывает по часам, а не от правки: ежедневно в заданное время, еженедельно в выбранный день недели и время, ежемесячно в выбранное число и время. Действие — любое: письмо, webhook, сообщение, клон, AI-саммари или баннер и запуск процесса.
Над чем выполнять — страница, папка, база или запись. Процесс, клон и AI-действия работают над этим предметом; письму и сообщению он даёт ссылку.
Время — местное, в часовом поясе того, кто создал правило (в интерфейсе — пояс браузера). Переход на летнее время час запуска не сдвигает.
Ежемесячно на 29–31-е: в коротком месяце правило срабатывает в последний его день — «31-го» значит «в конце месяца», февраль не пропускается.
Пропущенные запуски не догоняются: если сервис был недоступен, правило сработает один раз при восстановлении, а не за каждый пропущенный срок.
В списке правил видно расписание и время ближайшего запуска. Время можно поменять, не пересоздавая правило. Если предмет в корзине, запуск пропускается, а срок сдвигается на следующий.
Процессу, запущенному по расписанию, не нужна пауза затишья: он стартует сразу.
Через API — POST /v2/triggers (или /api/settings/triggers) с objectType: "schedule", событием daily, weekly или monthly и полями расписания: scheduleTime («ЧЧ:ММ»), scheduleWeekday (1 — понедельник … 7 — воскресенье, только у weekly), scheduleMonthDay (1–31, только у monthly), scheduleTimeZone (IANA, по умолчанию — пояс создателя). objectId — предмет действия. Время меняется через PATCH теми же полями; ближайший запуск — в schedule_next_at.
POST /v2/triggers
{ "objectType": "schedule", "objectId": "<id базы или записи>",
"eventType": "monthly", "scheduleMonthDay": 1, "scheduleTime": "08:00",
"actionType": "run_pipeline", "pipelineTemplateId": "<id процесса>" }
Изменение связанной записи
Событие linked_record_changed срабатывает у записи, когда меняется запись, на которую ссылается её поле связи. Правило пишут на свою базу — «когда поменяется связанный контрагент, пересчитай сводку», — поэтому предметом события выступает сама ссылающаяся запись, а не далёкая запись в другой базе.
Событие приходит одинаково на все три случая: связанную запись исправили, создали новую (она приходит уже со связью) и удалили существующую. Для расчётов это важно: новая проводка обязана пересчитать факт так же, как исправленная, а удалённая — вычесть себя. При удалении событие рассылается заранее, пока связи ещё целы: после удаления искать по ним было бы уже нечего.
Поле связи выбирается обязательно: у записи их бывает несколько, и следят обычно за одной. Событие доступно только правилам на базе данных. Несколько изменений связанной записи подряд дают одну доставку — пересчитать достаточно однажды.
Объединение последовательных изменений
События «Изменение заголовка» и «Любое изменение» от правок человека в редакторе отправляются, когда объект закрыли, или после 5 минут без новых изменений. Каждое новое автосохранение сдвигает срок доставки, поэтому последовательный ручной ввод создаёт одну доставку вместо серии писем или webhook-вызовов. Законченные действия — сохранение формы, запись через API, запись процессом — отправляются через секунду.
Для заголовка сохраняются значение до начала серии и окончательное значение.
Добавленные, изменённые, удалённые и перемещённые блоки накапливаются за всё окно ожидания.
Событие создания в редакторе ждёт так же и обновляет название и снимок записи по следующим этапам создания; созданное формой или через API уходит через секунду.
Если объект удалён до доставки, ожидающие события создания и изменения отменяются, а событие удаления обрабатывается сразу.
Очередь хранится в PostgreSQL, поэтому закрытие браузера и перезапуск worker не сбрасывают таймер и не теряют событие.
Действие «Создать клон»
Выберите тип нового объекта: страницу или запись БД.
Для страницы найдите контейнер-страницу или папку; для записи выберите целевую базу данных.
Сохраните триггер. При событии worker создаст объект с названием источника.
Перед созданием Vtorum ищет в выбранном контейнере объект того же типа с точно совпадающим названием. Если такой объект уже существует, новый не создаётся: существующая запись обновляется, а в существующую страницу добавляется ссылка.
Новая или найденная страница получает блок-ссылку на исходный объект. Если такая ссылка уже есть, второй блок не добавляется.
При клонировании записи в запись значения переносятся в доступные для записи поля с идентичными названиями и совместимыми типами. Вычисляемые и системные поля не копируются; пустое исходное значение очищает соответствующее поле существующего клона.
Если базы соединены relation-полями, новая или найденная запись связывается с исходной через эти поля; существующие связи найденной записи сохраняются, а двусторонняя relation синхронизируется обычным механизмом базы данных.
Операция выполняется атомарно. Идентификатор результата сохраняется в доставке триггера, поэтому повтор worker после временной ошибки не создаёт второй клон.
Автоматически созданный клон не запускает новую цепочку триггеров сам по себе. Это предотвращает бесконечное клонирование.
Администратор
Аккаунт, пространства и администрирование
В настройках аккаунта пользователь меняет собственный пароль. Владелец или администратор пространства управляет названием и участниками.
Отпечаток и Face ID, замок приложения
В настройках учётной записи первым пунктом стоит «Отпечаток и Face ID» (с 5.50.57): ключ подключается на устройстве и заменяет пароль при входе; включённый замок приложения закрывает его шторкой при каждом открытии и возврате в приложение спустя 15 секунд. Ключи привязаны к адресу сайта: ключ, заведённый на одном адресе, на другом не действует.
Удалили ключ в настройках — замок выключается сразу, без перезапуска; удалили последний ключ — замок выключен и на сервере.
Замок действует только там, где есть чем его снять: если на текущем адресе у вас нет ключей (они заведены на другом), шторка не включается, а уже включённая снимает себя сама (с 5.50.59) — запереть человека без ключа замок не может.
Если шторка всё же на экране, а палец не подходит, кнопка «Выйти из учётной записи» выводит со шторки; зайти снова можно паролем или кодом из письма.
Способы входа
В карточке «Способы входа» настроек аккаунта три галочки — три фактора защиты учётной записи:
Вход через каталог компании (SSO) — видна, только если домен адреса подключён к корпоративному входу компании;
Вход по коду из email;
Вход по паролю — включается, когда пароль задан.
Включённые способы действуют одновременно: при входе нужно пройти их все. Например, каталог и код — сначала страница входа компании, затем код из письма; пароль и код — сначала пароль, затем код. Порядок шагов постоянный: пароль, код, каталог. Галочка сохраняется сразу по нажатию; оставить нужно хотя бы одну. Если компания включила «Только корпоративный вход», галочку каталога снять нельзя — код и пароль добавляются к нему вторым фактором. Системный администратор видит и меняет те же галочки пользователя в «Администрирование → Пользователи и квоты».
Учётная запись, созданная каталогом компании, и существующая, впервые связанная с ним, получают один фактор — каталог. Если подключение компании удалили и не осталось ни одного действующего способа, вход по коду из письма открывается сам, чтобы учётная запись не оказалась заперта.
Под галочкой каталога есть подсказка: при отключении в каталоге компании доступ к её пространству снимется, а учётная запись и свои пространства останутся — войти в них можно кодом или паролем. Код приходит на рабочую почту, которую при увольнении обычно закрывают, поэтому стоит заранее задать пароль или сменить адрес на личный.
Запись базы и обычная страница
Страницу переносят в базу данных, и она становится записью. Обратный перенос тоже возможен: запись, брошенная ручкой на страницу или папку дерева (или перемещённая туда через «Ссылка / копия / перемещение в…»), выходит из базы и снова становится обычной страницей. Заполненные свойства при этом не удаляются: у страницы вне базы их негде показать, но если вернуть её в ту же базу, значения снова окажутся на месте.
Пояснения для новичка
Сто элементов интерфейса снабжены короткой подсказкой — от дерева и создания страницы до баз данных, доски, AI и администрирования. Пачкой они не приходят: подсказка показывается только у того элемента, который сейчас на экране, и один раз: отметка «просмотрено» хранится за учётной записью, поэтому закрытая на одном устройстве подсказка не выскочит на другом. Пока человек не открыл базу данных, ни одной подсказки про базы он не увидит — темп задаёт то, куда он заходит, а не таймер. Первый десяток закрывает почти все повседневные нужды. Каждую можно закрыть или отказаться от всех сразу кнопкой «Не показывать больше». Галочка Настройки → Оформление → Показывать пояснения для новичков включена по умолчанию; если её вернуть после отказа, подсказки начнутся заново. Когда в продукте появляется новая возможность, её подсказку увидят все — кроме тех, кто от пояснений отказался.
Оформление: дневная и ночная темы
Настройки → Оформление переключает тему: дневная, ночная или «автоматически» — как выбрано в системе устройства. Выбор применяется сразу и хранится в этом браузере: тема — свойство устройства, а не учётной записи, поэтому за рабочим столом и на телефоне она может быть разной.
Саморегистрация с подтверждением
Вход и регистрация — одна форма. Человек вводит email, и код подтверждения уходит на любой адрес: и на известный системе, и на незнакомый. Что произойдёт дальше, решается после подтверждения кода — известная активная учётная запись входит, незнакомый адрес переходит ко второму шагу с именем и согласиями. Новая учётная запись создаётся со статусом pending, поэтому пользователь не может войти до решения системного администратора.
Прежние входы. Если на этом браузере уже входили, в поле email есть стрелка вниз: она открывает список адресов, с которыми вход прошёл успешно, — последний сверху. Щелчок подставляет адрес, крестик убирает его из списка. Список хранится только в этом браузере (до восьми адресов), на сервер не уходит и пароли не содержит; вход через корпоративный каталог тоже запоминает адрес.
Пользователь вводит email, подтверждает код из письма, указывает имя, принимает юридические документы и отправляет заявку.
Если письмо с кодом не доставлено — например, адрес в спам-листе почтового провайдера и его сервер отвечает «bounced check filter», — экран входа говорит об этом прямо, вместе с ответом чужого сервера, и предлагает другой адрес. Отчёты о недоставке читаются из почтового ящика отправителя; такое письмо в очереди получает состояние «не доставлено».
Запасная отправка кода. Письмо с кодом входа или регистрации, которое вернулось отказом или по которому код не ввели за минуту, уходит второй раз — тем же текстом и с тем же кодом — через другой почтовый сервис (Unisender Go). Основной путь идёт через общий почтовый релей, адреса которого часть почтовиков (mail.ru, корпоративные шлюзы) принимает плохо. Домен, куда релей за последние 90 дней уже отказывал (кроме отказов «нет такого ящика»), релей больше не пробует: код туда сразу уходит через Unisender Go, а экран входа ничего особенного не показывает. Если Unisender не ответил, письмо идёт обычным путём. Повтор делается один раз и только пока код действует. Экран входа в это время пишет спокойным цветом: «отправляем повторно», затем «отправили повторно другим путём — проверьте и папку «Спам»». О недоставке он говорит, только если не сработал и запасной путь. Включается ключом UNISENDER_GO_API_KEY в настройках сервера; задержку задаёт MAIL_FALLBACK_DELAY_SECONDS (по умолчанию 60). Unisender добавляет в письмо ссылку отписки, и Яндекс из-за неё может отнести код к «Рассылкам». UNISENDER_GO_SKIP_UNSUBSCRIBE=true убирает ссылку, но включать его можно только после того, как поддержка Unisender разрешит отправку без отписки.
Администратор открывает Настройки → Администрирование → Заявки на регистрацию.
Действие «Подтвердить» переводит пользователя в статус active; после этого разрешён вход и при первом входе создаётся личное пространство.
Действие «Отклонить» переводит заявку в статус rejected. Её можно позднее подтвердить или удалить.
Пользователи со статусами pending и rejected не могут авторизоваться и не отображаются в выборе участников пространства.
Автоматическое подтверждение заявок
В том же разделе «Заявки на регистрацию» есть галочка «Подтверждать заявки автоматически»; она сохраняется сразу по нажатию. При ней заявки как таковой нет: человек подтверждает почту кодом, указывает имя и принимает условия (кнопка «Зарегистрироваться и войти») — и сразу оказывается в системе, со своим пространством. Учётная запись получает статус active с пометкой «Подтверждена автоматически»; экрана «заявка отправлена» и писем человеку нет, а системным администраторам приходит письмо о новой регистрации, подтверждённой автоматически. Уже ожидающие заявки галочка не трогает — их подтверждают вручную.
Юридические документы при регистрации
На вкладке Настройки → Администрирование → Системные объекты находятся внешние ссылки на политику обработки персональных данных, пользовательское соглашение, форму сообщения об ошибке и форму жалобы на опубликованный контент. В настройках самой публикации также можно разрешить экспорт в PDF. Изменения применяются без нового деплоя.
Ссылка на политику обязательна: пока она не задана, регистрация недоступна, а в форме показывается соответствующее сообщение.
Ссылка на пользовательское соглашение необязательна. Пока поле пустое, при регистрации остаётся одна галочка — согласие на обработку персональных данных. Как только ссылка задана, появляется вторая обязательная галочка со ссылкой на соглашение, и она же добавляется в подвал страницы входа.
Согласие фиксируется вместе с версией документа, моментом принятия и точным адресом, который видел пользователь. Если ссылку изменили, пока форма была открыта, заявка отклоняется с просьбой обновить страницу и подтвердить согласие заново.
Разделы администрирования
Разделы администрирования собраны в четыре группы. Настройки — «Объектное хранилище» и «Системные объекты». Пользователи — «Пользователи и квоты», «Текущие пользователи», «Заявки на регистрацию», «Создание учётной записи» и «Корпоративный вход». Тарифы — справочник тарифов и прайс. Разработка (внизу) — «Разработка» и «Журнал разработки». В «Пользователях и квотах» у каждого человека одинаковая карточка: имя и почта, под ними колонки «Тариф», «Облако» (лимит и занятое место), «Роли» и «Вход».
Владелец может удалить пространство — кнопка «Удалить пространство» стоит в строке названия, рядом с «Сохранить». На телефоне обе кнопки стоят под полем названия.
Системный администратор создаёт и удаляет пользователей, а также рассматривает заявки на регистрацию.
В «Пользователях и квотах» сохраняется подстрочный поиск по имени или email. У найденной учётной записи можно сменить тариф, изменить облачную квоту или удалить пользователя.
В настройках объектного хранилища задаётся часовой лимит выдачи файловых ссылок для одного пользователя. Изменение применяется без перезапуска API; старые профили используют значение 600.
При удалении пользователя его пространства передаются текущему администратору.
В корзине, под пояснением в шапке, две кнопки очистки с подсказками при наведении. «Очистить без вложенных» окончательно удаляет объекты, которые уже находились в корзине; их дочерние объекты без другого активного родителя сохраняются и перемещаются в корзину, а не становятся корневыми. «Очистить все» удаляет всё дерево удалённого: объекты корзины вместе со всеми вложенными на любой глубине. В обоих режимах объект, у которого есть другой живой родитель, остаётся на месте.
Файлы из хранилища удаляются только явно: при очистке корзины (файлы удалённых страниц и записей) и при замене аватара или логотипа. Физически файл стирается через неделю и лишь если он больше нигде не упомянут — ни на другой странице (например, скопированная картинка), ни в истории версий, ни в значениях свойств, настройках и комментариях. Файл, который перестал использоваться сам по себе (картинку убрали со страницы), остаётся: он нужен истории версий. Автоматического поиска «ничейных» файлов нет.
Администратор
Тарифы
У каждой учётной записи есть тариф (подписка). Он определяет объём облака и пакеты: совместную работу, оформление страниц («Внешний вид»), автоматизацию и интеграции пространства.
Simple — бесплатно: 20 ГБ, своё пространство для одного, без совместной работы, оформления страниц и автоматизации.
Simple Corporate — 1000 ₽/мес: 20 ГБ, совместная работа, без оформления страниц и автоматизации.
Advanced — 1000 ₽/мес: 100 ГБ, оформление и автоматизация в своём пространстве, без совместной работы.
Experience — 5000 ₽/мес: 500 ГБ, оформление и автоматизация в своём пространстве, без совместной работы.
Corporate — 7000 ₽/мес: 500 ГБ и все пакеты, включая совместную работу и интеграции пространства.
God — 10 000 ₽/мес: 2 ТБ и все возможности.
Совместная работа — приглашать людей участниками в своё пространство и самому участвовать в чужих. Оформление страниц — «Внешний вид» страницы, непрерывная лента картинок и видео без зазоров («Сливать с соседями»), обложка видео и активные зоны в картинках. Автоматизация — триггеры, процессы и создание ботов (системных пользователей с ключом API). Интеграции пространства — синхронизация участников из внешней системы компании, а в ближайших выпусках — вход через SSO из домена компании (например, Active Directory); решает тариф владельца пространства. Цены, объёмы и описания правит системный администратор; значения выше — начальные.
В Настройки → Тарифы и оплата прайс показан в две строки: сверху частные тарифы — без совместной работы, снизу корпоративные — с ней. Текущий тариф выделен, у остальных кнопка заявки на смену. Ниже — участники своих пространств с их тарифами; сам владелец в этих списках не показан, а пространство без других участников не показывается.
Над прайсом лежит лицевой счёт без рамок и значков: баланс (до 15 декабря 2026 под ним у всех написано «субсидия», потом надпись исчезает), следующий платёж и кнопка «Оплата». Щелчок по балансу открывает оборотную ведомость, кнопка — окно «Оплата по СБП» с суммой (по умолчанию — стоимость текущего тарифа; можно оплатить больше, про запас). Оба окна модальные: закрываются крестиком, Esc или щелчком мимо, а пока оплата отправляется, окно оплаты не закрывается. Пока СБП не подключён, оплата уходит заявкой администратору, который пополняет счёт вручную.
Как действуют ограничения
Лимит облака следует тарифу, пока администратор не выставил человеку личный лимит; личный лимит сохраняется при смене тарифа.
Размер одного загружаемого файла ограничен общим лимитом сервера — 2 ГБ. Системный администратор может задать человеку свой лимит в разделе «Пользователи и квоты», в колонке «Один файл» (в ГБ, до 15 ГБ), и вернуть общий кнопкой сброса. Файл больше 256 МБ уходит в хранилище частями по 64 МБ, по три одновременно: при обрыве связи или перезагрузке страницы загрузка продолжается с недостающих частей, а не с начала файла. Через API (/v2/files/upload-url) файл отправляется одним запросом, поэтому там лимит не больше 5 ГБ. Слишком большой файл отклоняется ещё до отправки, а сообщение называет лимит в гигабайтах; так же, в гигабайтах, сообщается и о превышении лимита облака. Файлы в публичных формах и комментариях к публикациям проверяются по общему лимиту.
Участником пространства становятся только при совместной работе у обоих: у того, кого добавляют, и у владельца пространства — напрямую, по ссылке-приглашению или интеграцией. Доступ к отдельной странице или базе («Доступное мне») тарифом не ограничен.
Переход на тариф без совместной работы выводит человека из чужих пространств, а других участников — из его собственных. Без оформления — оформление страниц его пространств (цвета, склейка, обложки видео, активные зоны) перестаёт отображаться и возвращается вместе с тарифом; без пакета эти настройки нельзя включить, а снять — можно. Без автоматизации — его триггеры и процессы перестают срабатывать, но не удаляются, а новых ботов завести нельзя (созданные работают).
Новые учётные записи получают тариф по умолчанию (изначально Simple); сотрудники, заведённые интеграцией, — Simple Corporate.
Где настраивается
Настройки → Администрирование → Тарифы — цены, объёмы облака и описания тарифов, расшифровки возможностей, тариф новых учётных записей и слепок прайса во Vtorum: две связанные базы (тарифов и «Пакеты»), которые система наполняет по справочнику, а вид и оформление настраиваются вручную. Тариф конкретного человека меняют в разделе «Пользователи и квоты», там же — личный лимит облака. Свою тариф пользователь видит в настройках аккаунта, в карточке облачного хранилища.
Администратор
Интеграции пространства с внешними системами
Пространство может получать состав участников из внешней системы. Первый поддержанный источник — Мегаплан. Механизм универсальный: следующий провайдер добавляется тем же разделом настроек и той же синхронизацией.
Кто подключает
Системный администратор — в любом пространстве.
Роль «Владелец пространства компании» — только в тех пространствах, где этот человек является владельцем. Роль выдаёт системный администратор в Настройки → Администрирование → Пользователи и квоты. Роли платформы не исключают друг друга: один человек может быть и модератором, и владельцем пространства компании.
Обычный администратор пространства интеграции не подключает: доступ, привязанный к внешнему источнику, — решение уровня компании.
Как это работает
Настройки → Мои пространства → пространство → вкладка «Интеграции» → «Мегаплан»: адрес аккаунта, токен доступа и права по умолчанию (по умолчанию — чтение). На телефоне вкладки настроек пространства переносятся на вторую строку, поэтому «Интеграции» может оказаться под остальными.
«Проверить» показывает, сколько сотрудников видно и сколько из них действующие, ничего не меняя в правах.
«Синхронизировать» создаёт учётные записи для действующих сотрудников и выдаёт им права на пространство. Регистрацию проходить не нужно: у таких учётных записей включён только вход по коду — человек указывает свою рабочую почту и вводит код из письма.
Далее синхронизация повторяется автоматически (раз в 15 минут) и её можно запустить вручную кнопкой.
Снятие прав
Сотрудник стал неактивен или уволен в источнике — права на пространство снимаются, причина видна в списке участников интеграции.
Сотрудник исчез из списка источника — права тоже снимаются, но только если источник ответил непустым списком: пустой ответ считается сбоем выгрузки и права не обнуляет.
Права, выданные вручную, интеграция не трогает и не понижает; владельца пространства она не разжалует.
Отключение интеграции снимает все права, которые она выдала: источник больше не отвечает за доступ, значит и доступа быть не должно.
Токен доступа хранится только в шифрованном виде и никогда не возвращается в API — в интерфейсе видны лишь последние символы. Сотрудники без адреса почты в источнике пропускаются: без почты вход по коду невозможен.
Администратор
Корпоративный вход (SSO) в пространство компании
Сотрудники компании входят во Vtorum своей рабочей учётной записью: пароль они вводят на странице сервера входа компании, во Vtorum он не передаётся. Роль в пространстве выдаётся по группам каталога, а уволенный или исключённый из группы сотрудник теряет доступ без участия администратора Vtorum.
Vtorum реализует один стандарт — OpenID Connect (вход по коду авторизации с PKCE, конфиденциальный клиент); SAML не поддерживается. Keycloak и Microsoft AD FS — не протоколы, а программы-серверы входа: они умеют OpenID Connect наряду с другими стандартами. Для них во Vtorum есть готовые умолчания; любой другой сервер с поддержкой OpenID Connect подключается вариантом «Другой сервер OpenID Connect».
Как проходит вход
Сотрудник вводит рабочую почту на экране входа. По домену почты Vtorum находит подключение компании и показывает кнопку «Войти через …» с названием из настроек.
Кнопка уводит на страницу сервера входа компании; там сотрудник вводит пароль (и второй фактор, если он включён у компании).
Сервер входа возвращает сотрудника во Vtorum. Vtorum проверяет токен (подпись, издателя, что токен выдан именно ему, срок), находит учётную запись по постоянному идентификатору из токена (sub), выдаёт роль по группам и открывает пространство.
При первом входе учётная запись создаётся сама, с тарифом Simple Corporate. Регистрация и одобрение администратором не нужны. Вместе с ней появляется и личное пространство сотрудника с приветственными страницами — как при обычной регистрации; вход при этом ведёт в пространство компании.
Каталог — один из факторов входа учётной записи, наравне с кодом и паролем (см. «Способы входа» в разделе об аккаунте). Если сотрудник добавил себе код или пароль, после каталога экран входа попросит и их. Если галочка каталога у учётной записи снята, вход через каталог не принимается.
Что поддерживается
Программа сервера входа
Адрес issuer
Claim с группами
Scope
Keycloak
<адрес>/realms/<realm>
groups — путь группы срезается до имени
openid profile email offline_access
Microsoft AD FS
<адрес>/adfs — Vtorum добавит сам
group
openid profile email allatclaims offline_access
Другой сервер OpenID Connect
как введено
задаётся вручную
openid profile email offline_access
offline_access обязателен для любой программы: на токене продления держится проверка, не отключён ли сотрудник в каталоге. У AD FS без allatclaims в токен не попадут ни почта, ни группы.
Что настроить на стороне компании
Администратор сервера входа компании заводит для Vtorum приложение (клиента):
Тип — конфиденциальный клиент OpenID Connect с кодом авторизации; PKCE (S256) Vtorum передаёт всегда.
Адреса возврата (redirect URI): https://notes.vtorum.net/api/auth/sso/oidc/callback и, для проверки на стенде, https://dev.vtorum.net/api/auth/sso/oidc/callback. Точный список показан в карточке настроек.
Адрес возврата после выхода — https://notes.vtorum.net (или тот, что указан в настройках подключения).
Разрешённые scope — из таблицы выше; в токен должны попадать почта (email), имя (name) и список групп.
Группы для Vtorum с общим префиксом, например Vtorum-Admins, Vtorum-Editors, Vtorum-Viewers. Группы без префикса Vtorum отбрасывает. Сотрудников включают в группы по нужной роли.
Сервер входа должен быть доступен из интернета: Vtorum сам читает его описание (/.well-known/openid-configuration), ключи подписи, обменивает код на токены и продлевает их.
Keycloak. Clients → Create client: тип OpenID Connect, Client authentication — On, Standard flow — On, Valid redirect URIs и Web origins — адреса выше. Секрет — на вкладке Credentials. Добавить клиенту scope offline_access и mapper «Group Membership» с именем claim groups (Add to ID token — On). Если пользователи приходят из AD через федерацию или брокер (например, AD FS за Keycloak), Vtorum работает только с Keycloak — отдельное приложение в AD FS не нужно.
Microsoft AD FS. Application Groups → «Server application accessing a web API»: у серверного приложения записать Client Identifier (это идентификатор клиента), указать redirect URI и сгенерировать секрет; у Web API идентификатор — тот же Client Identifier. Разрешить scope из таблицы, в правилах выдачи отдать E-Mail Address, Name и группы (Token-Groups, Unqualified Names → Group). У сотрудников в AD должен быть заполнен атрибут mail.
Что настроить во Vtorum
Настраивает владелец пространства компании (его тариф должен включать «Интеграции пространства» — Corporate или God) или системный администратор: Настройки → Мои пространства → пространство компании → вкладка «Интеграции» → «Корпоративный вход (SSO)».
Программа сервера входа — Keycloak, Microsoft AD FS или другой сервер OpenID Connect. Стандарт у всех один, выбор программы только подставляет умолчания: claim с группами, префикс и набор scope.
Название для экрана входа — им подписана кнопка «Войти через …».
Адрес сервера входа (и Realm для Keycloak), Идентификатор клиента и Секрет клиента — из настроек сервера компании. Секрет после сохранения не показывается — видны последние символы; при утере выпустите новый и сохраните заново.
Префикс групп Vtorum — общее начало имён групп, остальные группы отбрасываются. Группы и роли — строки вида Vtorum-Editors = editor; роли: admin, editor, commenter, viewer. Из нескольких групп действует старшая роль, регистр в именах групп не важен.
Роль без подходящей группы — «Вход запрещён» (рекомендуется: тогда пускают только тех, кто в группах Vtorum) или роль для всех сотрудников домена.
Домены компании — по одному в строке. Один домен может быть только в одном подключении: по нему экран входа выбирает сервер.
Срок сессии (по умолчанию 8 часов) и Адрес возврата после выхода.
Нажмите «Подключить», затем «Проверить»: Vtorum прочитает описание сервера входа и покажет его адреса. Ошибка здесь — почти всегда опечатка в адресе или realm либо сервер недоступен из интернета.
Проверьте вход сотрудником: он появится в списке «Сотрудники, входившие через каталог» с ролью и временем входа.
После проверки можно включить «Только корпоративный вход»: для доменов компании закрываются код на почту и пароль. Системный администратор Vtorum входит всегда — чтобы ошибка в настройке не отрезала того, кто её исправляет.
Подтверждение домена
Под списком доменов в той же карточке — «Подтверждение доменов»: у каждого домена отметка «подтверждён» или «не подтверждён». Ставит и снимает её только системный администратор Vtorum, проверив, что домен действительно принадлежит компании; владелец пространства видит состояние. Изменение вступает в силу после «Сохранить».
Системный администратор обычно не состоит в пространстве компании и вкладку «Интеграции» не видит. Для него есть Настройки → Администрирование → Пользователи → Корпоративный вход: список подключений всех пространств — пространство, владелец, сервер входа, результат последней проверки — и домены каждого с кнопками «Подтвердить» и «Снять подтверждение». Изменение применяется сразу, после подтверждения в окне.
Домен принадлежит только одному подключению. Он занимается при сохранении, даже пока не подтверждён, поэтому второе пространство с тем же доменом подключение не сохранит: Vtorum назовёт занятый домен и ничего не изменит. Если домен держит чужое пространство, системный администратор освобождает его там же кнопкой «Освободить».
Пока домен не подтверждён, новые сотрудники входят и получают учётную запись, а сотрудник, у которого учётная запись Vtorum с тем же адресом уже была, через каталог не войдёт — так чужой сервер входа не получит доступ к чужим страницам. После подтверждения такая учётная запись подхватывается со всеми страницами и доступами.
Доступ и его снятие
Сессия корпоративного входа живёт срок из настроек подключения, а не общие 30 дней.
Раз в полчаса Vtorum продлевает токен у сервера входа. Отказ (учётная запись отключена или удалена) — доступ к пространству компании снимается сразу: человек исключается из пространства, его сессии в нём гаснут. Авария сервера входа доступ не трогает.
Учётная запись Vtorum при этом остаётся вместе с собственными пространствами человека. Фактор «каталог» у неё снимается, вместо него включается вход по коду из письма, заданный пароль сохраняется; правило «Только корпоративный вход» на бывшего сотрудника больше не действует. Если человека вернут в каталог, следующий вход через него восстановит и связь, и членство в пространстве.
Изменились группы — роль пересчитывается. Не осталось группы Vtorum и роль по умолчанию не задана — членство в пространстве снимается. Роль владельца пространства каталог не понижает.
Выход из Vtorum уводит и на страницу выхода сервера компании: иначе на общем компьютере следующий вход произошёл бы молча.
Если вход не получается
«Для этого адреса корпоративный вход не настроен» — домена нет в подключении или подключение выключено.
«Каталог компании не выдал токен входа» или «нет адреса почты сотрудника» — не выдан нужный scope (у AD FS — allatclaims) или не заполнена почта в каталоге.
«Нет доступа: учётной записи не выдана ни одна группа Vtorum» — сотрудник не состоит в группах с префиксом Vtorum, их нет в карте «группа = роль», или группы не попадают в токен.
«Адрес почты не относится к этой компании» — домен почты из токена не входит в это подключение.
«Домен компании ещё не подтверждён…» — см. «Подтверждение домена».
Секрет клиента и токен продления хранятся только в шифрованном виде и наружу не возвращаются. Техническое описание подключения, маршрутов и схемы данных — docs/integration/CORPORATE_SSO.md.
Администратор
Вход и регистрация через Яндекс ID, Т-ID, Mail.ru и СберID
Под формой входа могут стоять кнопки Яндекс ID, Т-ID, Mail.ru и СберID. Человек нажимает кнопку, подтверждает вход у провайдера и возвращается во Vtorum: известный аккаунт входит сразу, новый проходит короткую регистрацию. Кнопка появляется, только когда суперадминистратор включил провайдера в Настройках → Администрирование → Вход через id-сервисы. В этом разделе у каждого провайдера есть пошаговая инструкция по подключению: где создать приложение, что указать, что скопировать и как проверить вход.
Как проходит вход
Из профиля берутся только имя и адрес почты. Телефон, дата рождения, пол и документы не сохраняются, токены провайдера тоже.
Если аккаунт у провайдера ещё не привязан, а почта в профиле на собственном домене провайдера (Яндекс: yandex.ru и др.; Mail.ru: mail.ru, inbox.ru, list.ru, bk.ru, internet.ru) либо администратор включил у провайдера «Доверять почте провайдера», она считается подтверждённой: запись с такой почтой привязывается и человек входит сразу, новому остаются имя и согласия. Для остальных адресов (и у Т-ID, где почты в профиле нет) Vtorum просит подтвердить почту кодом из письма: провайдеры не гарантируют, что почта подтверждена. Дальше — имя, согласия и заявка (или сразу вход при включённом автоподтверждении).
Почта на чужом домене без кода из письма (и без включённого доверия) никогда не открывает чужую запись. Вход через id-сервис — отдельный способ входа: он не добавляется к паролю и коду как дополнительный фактор.
Привязать и отвязать аккаунты можно в Настройках → Аккаунт → Способы входа → Привязанные аккаунты. Последний способ входа отвязать нельзя: сначала включите вход по коду.
Что настроить администратору
В кабинете провайдера создать приложение и указать адрес возврата https://notes.vtorum.net/api/auth/id/<провайдер>/callback (провайдеры: yandex, tid, vk, sber; кнопка Mail.ru — это VK ID с включённым провайдером Mail OAuth).
Во Vtorum ввести client_id и секрет; для VK ID — ещё сервисный ключ, для СберID — среду и клиентский сертификат (двусторонний TLS). Кнопка «Проверить настройки» проверяет заполненность, чтение сертификата и доступность адреса провайдера.
Т-ID по документации подключается письмом на tid@tbank.ru и доступен от 30 тысяч авторизаций в месяц; пока доступа нет, провайдера не включают.
Дополнить политику обработки персональных данных: имя и адрес почты поступают от выбранного id-сервиса.
Знаки на кнопках — официальные файлы самих провайдеров, кнопки стоят под «Войти с паролем». У VK ID нарушение дизайна — основание блокировки приложения: макет кнопки Mail.ru согласуйте с поддержкой VK ID. Т-ID может потребовать свой виджет, у СберID кнопка зелёная по гайду.
Пользователь
Импорт записей Plaud
Записи диктофона Plaud можно забирать во Vtorum автоматически. Подключение личное: его делает каждый в Настройки → Импорт → Plaud → Настройки кнопкой «Подключить Plaud» и входом в свой аккаунт Plaud. После входа Vtorum раз в несколько минут забирает новые записи во «Входящие → Plaud»; журнал синхронизаций — там же, в пункте «Импорт».
Если вход в аккаунт Plaud не был пройден до конца, в журнале импорта будет «Plaud не подключён: вход в аккаунт Plaud не завершён». Нажмите «Подключить Plaud» ещё раз и пройдите вход до конца — до возврата во Vtorum.
API
Интеграция ассистента пространства
Ассистент пространства отвечает не только в чате Vtorum. Внешняя система — бот в мессенджере, портал поддержки, собственный агент — может задать пространству любой вопрос одним HTTP-запросом и получить ответ модели вместе со ссылками на статьи, из которых он собран. Логика та же, что в чате: поиск источников по смысловому индексу, ответ модели, перечень процитированных страниц.
Как включить
Настройки → Пространства, выберите пространство и откройте вкладку «Интеграция ассистента». Вкладка доступна владельцу, администратору и редактору пространства.
Нажмите «Включить интеграцию». Vtorum выдаст адрес (он одинаков для всех пространств) и Bearer-токен (он у каждого пространства свой — именно токен определяет, о каком пространстве спрашивают).
Скопируйте адрес и токен во внешнюю систему.
Ассистент отвечает от имени того, кто выпустил действующий токен. Внешний запрос видит ровно те страницы, которые видит этот человек, и обращение к модели оплачивается его ключом AI. Если он потеряет доступ к пространству, интеграция перестанет отвечать: членство проверяется на каждом запросе.
Адрес и аутентификация
Метод POST, адрес https://notes.vtorum.net/api/public/assistant. Токен передаётся заголовком Authorization: Bearer <токен>. Тело запроса и ответ — application/json в кодировке UTF-8. Cookie не нужны и не используются: токен — единственный ключ.
question — обязательное, строка от 1 до 20 000 символов. Любой вопрос на естественном языке.
thread_id — необязательное, UUID диалога. Без него каждый запрос — отдельный разговор. Передайте thread_id из предыдущего ответа, чтобы ассистент помнил переписку: в контекст попадают последние 10 сообщений диалога.
Формат ответа
{
"answer": "Заявление подаётся за две недели [1]. Дни считаются календарными [2].",
"sources": [
{
"index": 1,
"title": "Отпуска и отгулы",
"url": "https://notes.vtorum.net/#/page/9a1c3f77-2b5e-4d2a-8f10-4c9b0d3e77aa",
"page_id": "9a1c3f77-2b5e-4d2a-8f10-4c9b0d3e77aa",
"excerpt": "Заявление на ежегодный отпуск подаётся не позднее чем за 14 дней…",
"score": 0.6412
}
],
"thread_id": "0f6b1b1e-6d1a-4a2e-9e3a-0c0b6e4c5d21",
"retrieved_sources": 8
}
answer — ответ модели. Ссылки внутри текста имеют вид [1], [2] и соответствуют полю index в sources.
sources — только процитированные статьи. Если модель сослалась на две из восьми найденных страниц, в списке будут две.
url — абсолютная ссылка на страницу Vtorum, её можно показать пользователю. page_id — идентификатор той же страницы для API V2.
excerpt — фрагмент страницы, попавший в контекст (до 320 символов), score — близость фрагмента к вопросу от 0 до 1.
retrieved_sources — сколько источников поиск передал модели. Пара «retrieved_sources больше нуля, а sources пуст» означает, что найденное модели не пригодилось, — это другая причина, чем «ничего не нашлось».
Ошибка возвращается тем же форматом, что и во всём API Vtorum: HTTP-код и тело с полями code, message и request_id — последний стоит сохранять в журнале внешней системы, по нему разбирают обращение.
401 unauthorized — заголовка Authorization нет, токен неизвестен, отозван или интеграция выключена.
400 validation_error — пустой question, длиннее 20 000 символов или thread_id не UUID.
403 forbidden — человек, от чьего имени работает интеграция, больше не состоит в пространстве. Выпустите токен заново от действующего участника.
404 object_not_found — переданный thread_id не принадлежит этой интеграции.
409 ai_not_configured / 409 assistant_model_missing — у пространства не настроена модель ассистента.
429 rate_limited — превышен лимит: 120 запросов в час на токен. В ответе приходит заголовок Retry-After с числом секунд до следующей попытки.
Пределы и правила
Один токен на пространство. Новый токен отменяет прежний немедленно.
Ответ строится только по проиндексированным страницам. Если смысловой индекс пространства не заполнен, ассистент честно ответит, что источников недостаточно, — состояние индекса видно на соседней вкладке.
Запросы к интеграции попадают в те же диалоги ассистента, что и чат: их видно в истории того человека, от чьего имени отвечает интеграция.
Адрес отвечает с заголовками CORS, поэтому обращаться можно и из браузера. Токен при этом становится видимым пользователю — для публичных сайтов вызывайте интеграцию со своего сервера.
Токен хранится в шифрованном виде и показывается в настройках только владельцу вкладки. Отозвать его можно двумя способами: «Выпустить новый токен» — если внешняя система остаётся, и «Удалить» — если интеграция больше не нужна.
API
Developer API V2
Developer API V2 совместим с основным контрактом Buildin V2. Базовый адрес: https://notes.vtorum.net/v2. Ниже приведён полный перечень операций вместе с параметрами, телами запросов и схемами ответов, автоматически полученный из OpenAPI приложения.
Эта страница — приложение на JavaScript, и curl получил бы от неё пустую оболочку. Для агентов и скриптов та же документация отдаётся текстом, без входа:
/llms.txt — оглавление: разделы со ссылками;
/doc.md (то же — /llms-full.txt) — вся документация одним Markdown;
/doc/<раздел>.md — один раздел, например /doc/database-forms.md; идентификатор раздела — тот же, что в якоре /doc#database-forms;
/doc с заголовком Accept: text/markdown — тоже Markdown; без него страница приходит с текстом уже внутри HTML.
Страница /doc открыта для поисковиков: у неё свои заголовок, описание и canonical, и она стоит в /sitemap.xml второй строкой после стартовой страницы. Раздел по адресу /doc/<раздел> ссылается canonical на всю документацию. Стартовая страница доступна по двум адресам: / — для гостя (вошедший сразу попадает в приложение) и /home — для всех, её открывает www.vtorum.net; canonical у обоих — корень. Несуществующий адрес страницы отвечает 404, адреса /api/ и /v2/ без входа — по-прежнему 401.
Авторизация
Создайте системного пользователя в Настройки → API для интеграций, выдайте ему доступ к нужным узлам обычным интерфейсом «Доступ», затем сохраните показанный один раз токен.
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true,
"description": "Pass after_block_id / before_block_id to move the block next to a sibling on the same page, and/or parent_block_id (a block id, or null for the page root) to change nesting. Without a neighbour the block goes to the end of the target parent. Structural placement blocks (child_page, child_database, child_folder) accept only these move fields — repositioning one also reorders the navigation tree — while their content and in_trash stay read-only here. The type payload is merged into the stored one; set a payload key to null to remove it.",
"properties": {
"parent_block_id": {
"type": [
"string",
"null"
],
"format": "uuid"
},
"after_block_id": {
"type": "string",
"format": "uuid"
},
"before_block_id": {
"type": "string",
"format": "uuid"
},
"in_trash": {
"type": "boolean"
}
}
}
}
}
}
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/ParentInput"
},
"title": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"description": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"properties": {
"type": "object",
"description": "Keys name properties (name, external key or id). number, formula and rollup take decimals and align; number takes {format, decimals (0-10 digits after the decimal comma when shown), align (left|center|right)}. rollup and linked_property take the RollupPropertyConfig / LinkedPropertyConfig shapes: related fields may be given by name or id, unknown keys are rejected with 400. Pass name to rename an existing property; type settings are replaced only when their block is sent. unique: true (or false) makes values of the property unique across records — send it on the property object, e.g. {\"ИНН\": {\"unique\": true}}; it is merged into the current settings and returned as unique on the property. Enabling it over existing duplicates fails with 409 unique_duplicates; a repeated value fails with 409 unique_violation. Supported: title, rich_text, number, select, status, date, url, email, phone_number, relation. hidden: true (or false) hides the property from table columns, view cards and field pickers, as the \"hide property\" checkbox does; it is accepted the same ways as unique, merged into the settings, returned on every property and rejected with 400 for the title property. A type block sent without unique or hidden keeps their previous values.",
"additionalProperties": true
},
"icon": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"cover": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"in_trash": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"is_inline": {
"type": "boolean"
},
"after_page_id": {
"type": "string"
},
"before_page_id": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"properties"
]
}
}
}
}
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/ParentInput"
},
"title": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"description": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"properties": {
"type": "object",
"description": "Keys name properties (name, external key or id). number, formula and rollup take decimals and align; number takes {format, decimals (0-10 digits after the decimal comma when shown), align (left|center|right)}. rollup and linked_property take the RollupPropertyConfig / LinkedPropertyConfig shapes: related fields may be given by name or id, unknown keys are rejected with 400. Pass name to rename an existing property; type settings are replaced only when their block is sent. unique: true (or false) makes values of the property unique across records — send it on the property object, e.g. {\"ИНН\": {\"unique\": true}}; it is merged into the current settings and returned as unique on the property. Enabling it over existing duplicates fails with 409 unique_duplicates; a repeated value fails with 409 unique_violation. Supported: title, rich_text, number, select, status, date, url, email, phone_number, relation. hidden: true (or false) hides the property from table columns, view cards and field pickers, as the \"hide property\" checkbox does; it is accepted the same ways as unique, merged into the settings, returned on every property and rejected with 400 for the title property. A type block sent without unique or hidden keeps their previous values.",
"additionalProperties": true
},
"icon": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"cover": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"in_trash": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"is_inline": {
"type": "boolean"
},
"after_page_id": {
"type": "string"
},
"before_page_id": {
"type": "string"
}
},
"additionalProperties": false,
"description": "locked: true locks the database against edits, locked: false unlocks it; both need write access, and a request that only unlocks is the single change accepted for a locked database. Pass parent (page_id or workspace: true) with optional after_page_id / before_page_id to move the database in the tree; write access to the current parent and to the destination is required."
}
}
}
}
{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"parent": {
"$ref": "#/components/schemas/ParentInput"
},
"properties": {
"type": "object",
"additionalProperties": true
},
"children": {
"type": "array",
"maxItems": 100,
"items": {
"$ref": "#/components/schemas/BlockInput"
}
},
"icon": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"cover": {
"anyOf": [
{
"$ref": "#/components/schemas/FileObject"
},
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
]
},
"in_trash": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"after_page_id": {
"type": "string",
"format": "uuid"
},
"before_page_id": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": false,
"description": "Pass parent to move the page to a new parent (page_id), to the workspace root (workspace: true) or into a database as a record (database_id); a record moves back into the tree with page_id / workspace and into another database with database_id. Moving requires write access to the page, to its current parent (or database) and to the destination. after_page_id / before_page_id position the page among the parent's children and cannot be combined with parent.database_id, because a record has no place in the tree. in_trash: false restores the page from trash. locked: true locks the page against edits, locked: false unlocks it; both need write access, and a request that only unlocks is the single change accepted for a locked page. To link another Vtorum page inline, put a mention span into rich_text: {\"type\":\"mention\",\"mention\":{\"type\":\"page\",\"page\":{\"id\":\"…\"}},\"plain_text\":\"Title\"}."
}
}
}
}
{
"type": "object",
"required": [
"object",
"id",
"created_time",
"last_edited_time",
"title",
"description",
"parent",
"properties",
"in_trash",
"is_inline",
"url"
],
"additionalProperties": true,
"properties": {
"object": {
"const": "database"
},
"id": {
"type": "string"
},
"created_time": {
"type": "string",
"format": "date-time"
},
"last_edited_time": {
"type": "string",
"format": "date-time"
},
"title": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"description": {
"type": "array",
"items": {
"$ref": "#/components/schemas/RichText"
}
},
"parent": {
"type": "object",
"additionalProperties": true
},
"properties": {
"type": "object",
"additionalProperties": true
},
"in_trash": {
"type": "boolean"
},
"locked": {
"type": "boolean"
},
"is_inline": {
"type": "boolean"
},
"unique_keys": {
"type": "array",
"maxItems": 20,
"description": "Record uniqueness keys; replaces the current list, [] removes all. Each key: {name, properties: [name | schema key | id] (1–6), where?: query filter}. The combination of values must not repeat; records with an empty key field and records in trash are not checked; text is compared case-insensitively. Saving a key over existing duplicates fails with 409 unique_duplicates. A single property is made unique with config.unique = true. Writes that repeat a key fail with 409 unique_violation (details.record_id — the existing record).",
"items": {
"type": "object",
"required": [
"name",
"properties"
],
"properties": {
"name": {
"type": "string"
},
"properties": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 6
},
"where": {
"type": [
"object",
"null"
],
"additionalProperties": true
}
}
}
},
"url": {
"type": "string"
},
"icon": {},
"cover": {}
}
}
Block
{
"type": "object",
"required": [
"object",
"id",
"parent",
"created_time",
"last_edited_time",
"has_children",
"in_trash",
"type"
],
"additionalProperties": true,
"properties": {
"object": {
"const": "block"
},
"id": {
"type": "string"
},
"parent": {
"type": "object",
"additionalProperties": true
},
"created_time": {
"type": "string",
"format": "date-time"
},
"last_edited_time": {
"type": "string",
"format": "date-time"
},
"has_children": {
"type": "boolean"
},
"in_trash": {
"type": "boolean"
},
"type": {
"type": "string",
"description": "Any block type — see the full list in BlockInput. Every editor type can be created and patched; reads may also return unsupported (an unrecognized imported block) and child_page / child_database / child_folder placements."
}
}
}
BlockInput
{
"type": "object",
"required": [
"type"
],
"additionalProperties": true,
"description": "Block types. WRITABLE (create/patch): paragraph, heading_1..heading_4, bulleted_list_item, numbered_list_item, to_do, quote, code, callout, divider, bookmark, embed, embedded_database_view, image, video, pdf, file, table (+table_row children), toggle, equation, link_to_page, ai_request, mermaid, drawing_board, mindmap, html_embed, synced_block, template, table_of_contents, breadcrumb, signature, crypto. There is NO audio type: put audio into a file block — the editor renders an audio player by content type. child_page, child_database, child_folder are structural placements: appending one places an EXISTING child node on the page; PATCH only moves them. unsupported is read-only (an imported block Vtorum did not recognize). Media payload (image, video, pdf, file, html_embed): {type:\"file\", asset_id} or {type:\"file\", file:{url}} from upload-url, plus caption (plain string or rich-text array); html_embed takes an uploaded text/html asset plus optional height_px, width_px, full_height. mermaid payload: {source} — the diagram text (stored as editor_text, the same as a code block; reads return editor_text); optional source_height_px / preview_height_px (96..2400) set the height of the code and diagram windows. drawing_board payload: {width, height, background, elements} — elements are shapes {id, type: rectangle|rounded_rectangle|ellipse|diamond|text, x, y, width, height, text, stroke, fill, strokeWidth, fontSize, textAlign, textVerticalAlign, layer}, paths {id, type: path, points: [{x, y}, …≥2], stroke, strokeWidth} and connectors {id, type: connector, from: {x, y, elementId?, side?}, to: {…}, text, shape: straight|elbow}; colors are hex (#1f2937). PATCH replaces elements as a whole. mindmap payload: {nodes: [{id, title, parent_id, page_id?, collapsed?}]} — exactly one root with parent_id null, every parent_id must exist, no cycles; root_id is computed; page_id must be a page you can read; placement_id is filled by the editor. Empty nodes (or {title}) creates a single root. signature: create an empty block — the server signs the page with the token user key; its fields cannot be set or patched (moving and trashing are allowed). crypto: client-side encrypted vault, visible only to its creator. synced_block, template: rich_text like a paragraph. table_of_contents, breadcrumb: no payload, rendered from the page. embedded_database_view payload: {database_id, view_id} — both ids must point to an existing database and one of its views; the block renders that view inline. Optional visible_view_ids (views of the same database, in tab order; view_id must be among them) turns the block into tabs, show_view_switcher: false hides the tab bar. Without visible_view_ids the block shows view_id alone. Size: width_px or width_percent (inside a column) and height_px; with a height the records scroll inside the block. table payload holds the grid options, its rows are table_row children with a cells array. Columns: there are no column/column_list wrapper blocks. To place blocks side by side, give CONSECUTIVE top-level blocks the same column_group_id (any uuid) inside their type payload (e.g. inside \"image\"), with column_index 0,1,2… per column and an optional column_ratio percentage (equal shares by default). Blocks sharing a column_index stack vertically in that column. The same keys come back on reads.",
"properties": {
"type": {
"enum": [
"paragraph",
"heading_1",
"heading_2",
"heading_3",
"heading_4",
"bulleted_list_item",
"numbered_list_item",
"to_do",
"quote",
"code",
"callout",
"divider",
"bookmark",
"embed",
"embedded_database_view",
"image",
"file",
"video",
"pdf",
"table",
"table_row",
"toggle",
"equation",
"link_to_page",
"ai_request",
"mermaid",
"drawing_board",
"mindmap",
"html_embed",
"synced_block",
"template",
"table_of_contents",
"breadcrumb",
"signature",
"crypto"
]
},
"children": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"ai_request": {
"$ref": "#/components/schemas/AiRequestInput"
}
}
}
AiRequestInput
{
"type": "object",
"additionalProperties": false,
"description": "AI request composer block. Create it with a prompt and optional attachments, then execute it via POST /blocks/{block_id}/ai-request/run.",
"properties": {
"request_type": {
"enum": [
"text",
"image",
"audio",
"speech"
],
"default": "text"
},
"prompt": {
"type": "string",
"maxLength": 100000
},
"raw_prompt": {
"type": "boolean",
"default": false,
"description": "Image requests only: send the prompt to the image model verbatim, skipping the conversational prompt-rewrite step. Use when the prompt is already a finished visual prompt and series consistency matters."
},
"image_format": {
"enum": [
"1:1",
"3:2",
"2:3",
"16:9",
"9:16",
"3:1"
],
"description": "Image requests only: frame format sent to the image model as an explicit size/aspect-ratio parameter. Omit to use the workspace AI settings."
},
"attachments": {
"type": "array",
"maxItems": 20,
"description": "Asset ids uploaded via /files/upload-url (owned by the token user).",
"items": {
"oneOf": [
{
"type": "string",
"format": "uuid"
},
{
"type": "object",
"required": [
"asset_id"
],
"properties": {
"asset_id": {
"type": "string",
"format": "uuid"
}
}
}
]
}
},
"speech_voice": {
"type": "string",
"maxLength": 200
},
"speech_speed": {
"type": "number",
"minimum": 0.25,
"maximum": 4
}
}
}
{
"type": "object",
"properties": {
"filter": {
"type": "object",
"description": "Dates: this_week, past_week, next_week, this_month, past_month, next_month, this_quarter, past_quarter, next_quarter, this_year, past_year, next_year are calendar periods in the time zone of the viewer (for a token — its system user); relative takes {unit: day|week|month|quarter|year, offset: integer}; past_7_days / past_30_days stay rolling windows; date_range takes {from, to} where a bound is {\"date\": \"YYYY-MM-DD\"} or {\"today_offset\": integer} and an empty bound leaves the period open. For people, created_by and last_edited_by the value is a user id or \"@me\" — the current user (for a token, its system user). Anything else is rejected with 400.",
"additionalProperties": true
},
"sorts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
}
},
"start_cursor": {
"type": [
"string",
"null"
]
},
"page_size": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20
}
}
}
PipelineDefinition
{
"type": "object",
"description": "A tree of steps starting at entry: every step except entry is referenced exactly once (next, yes or no), at most 50 steps.",
"required": [
"schema",
"entry",
"steps"
],
"properties": {
"schema": {
"const": 1
},
"entry": {
"type": "string",
"description": "Key of the first step"
},
"steps": {
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/PipelineStep"
}
},
"guard_own_changes": {
"type": "boolean",
"description": "Do not start again over the same subject for 120 s after this pipeline changed it."
}
}
}
{
"type": "object",
"required": [
"from"
],
"description": "page_text, title, asset_text — no extra keys; property and property_values need property_id; step needs step; const needs value; record takes the whole subject record; database_table takes all rows of database_id (any database of the workspace; defaults to the subject database). Relations come as arrays of record ids; in table rows empty values are omitted.",
"properties": {
"from": {
"enum": [
"page_text",
"title",
"property",
"asset_text",
"step",
"const",
"record",
"property_values",
"database_table"
]
},
"property_id": {
"type": "string"
},
"step": {
"type": "string"
},
"value": {
"type": "string"
},
"database_id": {
"type": "string"
}
}
}
PipelineProcess
{
"type": "object",
"required": [
"fn"
],
"description": "code is a function body: input (text), data (structure of integral sources), subject, steps and console.log are available; return the result. Synchronous, no network, files or timers.",
"properties": {
"fn": {
"enum": [
"none",
"template",
"ai",
"code"
]
},
"template": {
"type": "string"
},
"prompt": {
"type": "string"
},
"model": {
"type": "string"
},
"max_tokens": {
"type": "integer"
},
"code": {
"type": "string",
"maxLength": 20000
},
"timeout_ms": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"default": 2000
}
}
}
PipelinePut
{
"type": "object",
"required": [
"to"
],
"description": "property writes property_id of the subject record, converted to the property type (a number returned by code stays a number); email_other needs recipient_email; webhook needs url; message needs recipient_user_id; ai_function needs function_key. records_create creates records in database_id from the step result — an array of {title, properties} (properties by name, schema key or id, converted like property); up to 1000 per step, all or nothing; upsert_key (a property) updates the record with the same key value instead of creating a duplicate. The step output is {ids, created, updated}. records_lock locks (or, with locked:false, unlocks) the records whose ids the step returns — records of any database in the workspace the run owner can edit; up to 5000 per step, all or nothing; unlocking needs a workspace owner or admin as the run owner; no change events are raised; output {ids, locked, skipped}. A locked record rejects every edit and deletion with 423 node_locked, including writes by other pipelines (failed without retries).",
"properties": {
"to": {
"enum": [
"variable",
"property",
"block_append",
"title",
"email_self",
"email_other",
"webhook",
"message",
"ai_function",
"records_create",
"records_lock"
]
},
"locked": {
"type": "boolean",
"description": "records_lock only: false unlocks. Default true."
},
"property_id": {
"type": "string"
},
"database_id": {
"type": "string",
"description": "records_create only."
},
"upsert_key": {
"type": "string",
"description": "records_create only: name, schema key or id of the key property."
},
"recipient_email": {
"type": "string"
},
"url": {
"type": "string"
},
"recipient_user_id": {
"type": "string"
},
"function_key": {
"enum": [
"page_summary",
"banner_generation"
]
}
}
}
Используйте возвращённый file object при создании блока или свойства.
API
API: MCP-сервер
MCP (Model Context Protocol) — способ, которым нейросетевые клиенты и агенты подключают внешние системы: вместо описания API они получают список инструментов и вызывают их. Вторум отдаёт весь Developer API V2 набором таких инструментов по адресу https://notes.vtorum.net/mcp.
Войти можно двумя способами. От своего имени — клиент сам приводит вас в браузер, вы разрешаете доступ, и он работает с вашими правами. Токеном системного пользователя — тем же, которым ходят в Developer API V2; права такой интеграции выдаются вручную на конкретные объекты. Cookie браузера на самом /mcp не работают ни в одном из случаев: сервер смотрит только на токен.
Вход от своего имени (OAuth)
Клиенту достаточно адреса https://notes.vtorum.net/mcp без заголовка Authorization — остальное он сделает сам по спецификации MCP: прочитает /.well-known/oauth-protected-resource, зарегистрируется, откроет браузер и обменяет код с PKCE на токен. В браузере вы входите во Вторум как обычно — в том числе через корпоративный вход, если он в пространстве настроен, — и видите, какая программа просит доступ и какие права получит.
права при вызовах — ваши собственные: клиент видит ровно то, что видите вы в интерфейсе, а закрытая от вас страница останется закрытой. Отдельного окна «Доступ» для такого подключения не нужно;
в истории правок изменения записаны на вас — по ним видно, что сделано вашей рукой через MCP-клиент;
доступ выдаётся в том пространстве, которое было открыто в момент согласия. Нужен другой — переключите пространство и подключите клиент заново;
доступ отзывается в Настройки → API для интеграций → Доступы MCP-клиентов: кнопка «Отозвать» закрывает его немедленно. Клиент, который умеет выходить сам, отзывает свой токен при отключении сервера;
доступ продлевается сам: вместе с токеном клиент получает токен продления (grant_type=refresh_token) и меняет его на новую пару, не беспокоя вас окном согласия. Токен доступа живёт месяц, продление — полгода, и этот срок считается заново при каждом продлении: нужный вам агент не замолчит, брошенный перестанет работать сам. Каждое продление выдаёт новый токен продления и гасит прежний — предъявив прежний повторно, клиент получит invalid_grant.
Вход токеном системного пользователя
Заведите системного пользователя в Настройки → API для интеграций и выдайте ему нужные скоупы.
Откройте ему доступ к нужным страницам и базам обычным окном «Доступ» — так же, как человеку.
Сохраните показанный один раз токен. Он отзывается там же: «Выпустить новый токен» отменяет прежний немедленно, «Удалить» закрывает интеграцию целиком. Подробности — в разделе «Developer API V2».
заголовок Authorization: Bearer <токен> нужен на каждыйPOST /mcp: сессий сервер не хранит, состояние целиком в токене, и initialize ничего не запоминает;
скоупы токена (pages.read, pages.write, databases.read, databases.write, automation.read, automation.write и остальные) решают, какой вызов пройдёт. tools/list при этом отдаёт все инструменты — список собран из OpenAPI и от токена не зависит; нехватка скоупа видна при вызове: результат приходит с isError: true и текстом вроде forbidden: …;
доступ проверяется ещё и на каждый объект, от имени владельца токена: тот же вызов на закрытую от него страницу вернёт результат с isError: true и кодом forbidden, а не ошибку протокола;
страницы интеграция создаёт только под явно выданным родителем: вызов createPage без parent отвечает 403 «System integrations may create pages only under an explicitly granted parent» — укажите page_id или database_id, к которым у неё есть доступ.
В пространстве с корпоративным входом за интеграцией может стоять учётная запись каталога компании. Владелец или администратор пространства проходит авторизацию за бота сам — кнопкой «Авторизовать в каталоге» в карточке системного пользователя, — указав каталогу техническую учётную запись или свою. Привязка проверяется на каждом вызове V2 и MCP: если её сняли, токен отвечает 401 с просьбой авторизовать бота заново. Когда в настройках корпоративного входа включено «Системные пользователи работают только после авторизации в каталоге», токен без привязки не принимается вовсе. Права на объекты по-прежнему выдаются вручную и от способа авторизации не зависят; администратору каталога нужно внести второй адрес возврата — /api/auth/sso/bot/callback.
Отказ входа — это ошибка HTTP в формате V2, а не JSON-RPC: без заголовка Authorization приходит 401 unauthorized с сообщением Authentication required, с неизвестным или отозванным токеном — тот же 401 unauthorized с сообщением Invalid API token. GET /mcp отвечает 405: потока событий сервер не предлагает, ответ всегда приходит телом того же POST.
Подключение клиента
От своего имени — адреса достаточно, заголовок не нужен: клиент сам откроет браузер и приведёт вас на экран согласия.
claude mcp add --transport http vtorum https://notes.vtorum.net/mcp
Токеном системного пользователя — тем же адресом с заголовком. Так подключают агента, за которым не стоит человек.
Claude Desktop и другие клиенты с файлом настроек — блоками mcpServers выше: с headers для токена и без них для входа от своего имени.
Как устроено
транспорт — Streamable HTTP: один POST /mcp с сообщением JSON-RPC 2.0, ответ приходит телом того же запроса; поток событий не нужен, сессий сервер не хранит;
методы — initialize, tools/list, tools/call, ping; версии протокола 2024-11-05, 2025-03-26 и 2025-06-18;
инструментов столько же, сколько операций в V2, и называются они так же, как operationId в OpenAPI: getPage, updatePage, queryDatabase, createDatabaseView, searchContent, runPipeline и остальные;
аргументы повторяют запрос: параметры адреса и строки запроса — своими именами, тело — свойством body, заголовки — if_match и idempotency_key. Схема аргументов у каждого инструмента взята из того же OpenAPI, что и справочник на этой странице;
ответ приходит текстом JSON и структурированным полем; отказ — результатом с пометкой ошибки и причиной, а не обрывом соединения, чтобы агент мог исправить аргументы.
Права
Вызов инструмента — это и есть обращение к V2: сервер выполняет настоящий запрос к /v2/... с предъявленным токеном. Поэтому проверки не повторяются второй реализацией, а совпадают буквально: те же скоупы токена, те же права на объект, те же ограничения категории и пространства.
Права применяются от имени владельца токена — и это либо вы сами, если вошли от своего имени, либо системный пользователь, если токен его. В личном подключении это ровно ваши права из интерфейса, выдавать доступ отдельно не нужно; у системного пользователя права выдаются вручную окном «Доступ». В обоих случаях закрытая от владельца токена страница останется закрытой, а без скоупа pages.write правка не пройдёт и через MCP.
Кто подключён, видно вызовом getCurrentIdentity: личный доступ отвечает object: "user" с вашим именем, а название программы лежит в authorization.client_name; токен системного пользователя — object: "bot_user" с именем интеграции.
Ошибки протокола
Беда с самим сообщением — ответ JSON-RPC с кодом ошибки и обычным HTTP 200: сервер не сломался, не так составлен запрос.
-32700 Parse error — тело не разобрать как JSON: обрыв, пустое тело, не-JSON;
-32600 Invalid Request — JSON верен, но это не сообщение протокола (42, [], строка) или в нём нет method;
-32601 — метод неизвестен, -32602 — неизвестный инструмент в tools/call.
Отказ самого инструмента (нет прав, объект не найден, не сошлись аргументы) — не ошибка протокола: приходит обычный результат с isError: true и причиной текстом, чтобы агент исправил вызов сам.
Простаивающее соединение
Соединение, в которое больше минуты ничего не отправляли, закрывается со стороны сервера. Клиент, который держит его открытым и присылает следующий вызов в то же соединение, получает обрыв — в Claude Code он выглядит как ECONNRESET, в других клиентах как RemoteDisconnected. Это не отказ сервера: повторный вызов по новому соединению проходит обычным порядком.
при редких вызовах (реже раза в минуту) выключите в клиенте повторное использование соединений либо включите повтор запроса при обрыве — большинство клиентов умеет и то, и другое;
обрыв всегда приходит до ответа, то есть на запросе, который сервер не читал: повторять его безопасно, ничего не выполнится дважды.
Токен обязателен на каждом вызове, но добывать его вручную нужно только для системного пользователя: при входе от своего имени клиент получает токен сам и подставляет его без вашего участия. По cookie браузера MCP-сервер не работает ни в одном из случаев — это та же граница, что и у Developer API V2: токен живёт отдельно от сессии человека и отзывается отдельно.
API
API: представления базы
Представление — это сохранённый способ смотреть на базу: вид (таблица, список, доска, галерея, календарь, график, форма), отбор записей, порядок, группировка и оформление. Через API их можно перечислить, завести, настроить, поставить по умолчанию и удалить — всё то же, что делает человек в интерфейсе базы.
GET /v2/databases/{id}/views — список представлений базы в порядке показа. Scope databases.read.
GET /v2/database-views/{id} — одно представление со всеми настройками. Scope databases.read.
POST /v2/databases/{id}/views — создать представление; настройки можно передать сразу вместе с именем. Scope databases.write.
PATCH /v2/database-views/{id} — изменить имя, вид, фильтр, сортировки, группировку, колонки и оформление. Scope databases.write.
POST /v2/database-views/{id}/default — сделать представлением по умолчанию. Scope databases.write.
Права проверяются по самой базе: чтение — read, любое изменение — edit. Заблокированная база представления менять не даёт.
Настройки представления
name — имя, type — вид: table, list, board, gallery, calendar, chart, form, edit_form.
filter — отбор записей теми же словами, что и в POST /v2/databases/{id}/query: условие вида { property, <тип>: { <оператор>: значение } } либо группа and / or. Фильтр из разового запроса переносится в представление копированием.
В условиях по полям «Пользователь», «Создал» и «Изменил» значение — идентификатор пользователя или "@me", то есть «Я»: { "property": "Руководитель", "people": { "contains": "@me" } }. «Я» хранится признаком и у каждого разворачивается в него самого — одно представление «Мои» работает для всех. В запросе через токен «Я» — системный пользователь токена. Любое другое значение ("me", "Я", имя) — ошибка 400: опечатка иначе дала бы представление, пустое у всех без объяснений.
Периоды по датам — календарные, в часовом поясе из профиля смотрящего (для токена — его системного пользователя): this_month, past_month, next_month, так же _week (неделя с понедельника), _quarter, _year; «позапрошлый месяц» — { "date": { "relative": { "unit": "month", "offset": -2 } } }. Месяц начинается 1-го числа: 1 октября «этот месяц» — только октябрь. Скользящие окна называются прямо — past_7_days, past_30_days; прежде past_month молча превращался в 30 дней, теперь он означает календарный месяц. В интерфейсе фильтр по дате предлагает один вариант — «С … по …»: { "date": { "date_range": { "from": { "today_offset": -7 }, "to": { "date": "2026-10-01" } } } }. Граница — конкретная дата или «сегодня» со сдвигом в днях (минус — в прошлое); незаполненная граница означает открытый конец периода. Все прежние операторы продолжают работать в API и в уже настроенных представлениях.
sorts — порядок: [{ "property": "Срок", "direction": "descending" }]. Первый элемент важнее последующих.
property_layout — колонки: [{ "property": "Название", "width": 320, "hidden": false }]. Ширина в пикселях, от 40 до 1200.
layout — оформление вида: row_height (compact или comfortable), wrap_cells, page_size, card_size, card_properties, настройки графика и формы — те же ключи, что записывает интерфейс. Цвет строк таблицы — row_color_property: имя, ключ или UUID перечислимого поля (выбор, статус, множественный выбор); сохраняется как row_color_property_id, null снимает окраску. Другой тип поля — ошибка 400.
Свойство называют как удобно: собственным идентификатором, внешним ключом id из схемы базы или человеческим именем. Незнакомое имя — ошибка 400, а не молчаливый пропуск: фильтр по несуществующему свойству дал бы пустое представление без объяснений.
В ответе property — это ключ свойства, поле id из схемы базы: внешний ключ, если он задан (например title), иначе UUID свойства. Имя для этого не годится — его переименуют, и сохранённая ссылка перестанет совпадать. Имя приходит рядом, в property_name (в сортировках, группировке и колонках). Ответ можно отправить обратно в PATCH как есть: property_name при записи не учитывается.
null в любом из полей filter, sorts, grouping, property_layout, layout снимает настройку. Поля, которых нет в теле запроса, остаются как были.
В ответе рядом с filter лежит filter_ast — то, что хранится на самом деле. Представления настраивают и в интерфейсе, где условий больше, чем в проводном словаре API; такое условие отдаётся с filter: null, а его устройство видно в filter_ast. Придумывать для него проводное написание нельзя — оно бы не читалось обратно.
Порядок вкладок
PUT /v2/databases/{id}/views/order с { "view_ids": ["…", "…"] } выстраивает вкладки за один запрос: названные — первыми в указанном порядке, остальные — следом, как были. Одну вкладку переставляют полем position в PATCH /v2/database-views/{id}: { "after": "<id>" }, { "before": "<id>" } или { "index": 2 } (с нуля). Первая вкладка и есть представление по умолчанию.
Если разным страницам нужны разные наборы вкладок одной базы, порядок базы трогать не нужно: встройте базу блоком и задайте ему свои вкладки — visible_view_ids в payload блока embedded_database_view.
Удаление последнего встроенного вида базы на странице (в редакторе или DELETE /v2/blocks/{id}) снимает и размещение базы под этой страницей: в дереве она больше не висит под страницей, блок-ссылка на базу не появляется. Сама база и её основное размещение остаются; если другого места у базы не было, она переезжает в корень пространства. DELETE блока child_database снимает размещение так же, как «Убрать со страницы»: единственное размещение уводит объект в корзину.
Дочерний объект показывают на странице блоком подобъекта, а не ссылкой: child_page, child_database или child_folder в PATCH /v2/blocks/{id}/children, например { "type": "child_database", "child_database": { "database_id": "<id>" } }. Блок объекта не создаёт: объект уже должен лежать под этой страницей (создайте его с parent этой страницы или перенесите сюда). Сервер сам проверит вид объекта, подставит его размещение и название. Ответы: 400 — объект не под этой страницей или вид блока не совпадает с видом объекта (в сообщении сказано, какой нужен); 409 — блок этого объекта на странице уже есть. link_to_page остаётся для ссылок на объекты, лежащие в другом месте.
Все виды блоков
Через API создаются и правятся все виды блоков редактора, в том числе схема Mermaid, доска для рисования, mindmap, HTML-вставка, синхронизированный блок, шаблон, оглавление, «хлебные крошки», подпись и личный сейф. Только для чтения остаётся unsupported — метка блока из импорта, который Vtorum не распознал. Формат содержимого тот же, что хранит редактор:
Текстовые блоки (абзац, заголовки, списки, цитата, выноска, задача) — источник текста в rich_text. Поле editor_text — кэш редактора: при записи через API его можно не передавать, а если передано и расходится с rich_text (например, без упоминаний), используется rich_text. Поле editor_html не хранится: сервер убирает его при сохранении.
mermaid — { "source": "flowchart LR\n A --> B" }; при чтении текст схемы приходит в editor_text.
drawing_board — width, height, background и elements: фигуры (rectangle, rounded_rectangle, ellipse, diamond, text) с координатами и текстом, пути (path, не меньше двух точек) и стрелки (connector с from и to, можно привязать к фигуре через elementId).
mindmap — nodes с id, title и parent_id: корень ровно один, родители существуют, циклов нет. Узел может вести на страницу (page_id), если вызывающий её читает.
html_embed — загруженный HTML-файл, как у картинки, и высота блока.
signature — создаётся пустым, сервер сразу подписывает страницу ключом пользователя токена. Поля подписи с клиента не принимаются, править подпись нельзя — только переносить и удалять.
Ошибочное содержимое — элемент доски без id, путь из одной точки, ветка карты без родителя — отклоняется с 400 и указанием поля, а не пропадает потом в редакторе молча.
Представление по умолчанию
Отдельного признака у представления нет: базу открывает первое по порядку представление, показывающее записи, — формы пропускаются. Поэтому POST /v2/database-views/{id}/default переносит представление в начало списка, и в ответе оно приходит с is_default: true. Форма, перенесённая в начало, базу не открывает и приходит с is_default: false; по умолчанию она станет, только если других представлений нет.
Порядок один на всё пространство, но каждому человеку база открывает то представление, которое он смотрел последним. Новый порядок он увидит при первом открытии базы, а тот, кто уже выбрал себе другой вид, останется в нём.
Последнее представление удалить нельзя: база без представления не открывается, поэтому такой запрос отвечает 409. Удаление возвращает { "object": "database_view", "id": "…", "deleted": true }. Встроенные блоки, которые показывали удалённый вид, переходят на живой: вид убирается из их вкладок (visible_view_ids), а открываемым (view_id) становится первая оставшаяся вкладка; если вкладок нет — блок остаётся без вида, и его выбирают заново.
Переименование и настройка колонок
Колонки — это свойства базы, их меняют запросом PATCH /v2/databases/{id} в поле properties. Ключ объекта называет существующее свойство (имя, внешний ключ или UUID), новое имя передаётся в name:
linked_property показывает значение поля связанной записи как есть, со всеми его свойствами отображения.
rollup сводит значения по функции: show_original (по умолчанию), show_title, show_unique, count, count_values, sum, average, min, max.
Незнакомый ключ, связь не из этой базы или поле, которого нет в связанной базе, — ошибка 400 с перечнем допустимого. Пустое поле, которое никогда ничего не покажет, в схему не попадает.
Значения считаются сразу у всех существующих записей, а дальше — при каждой записи через API или интерфейс и при изменении связанной записи.
В одном запросе создания базы вычисляемое поле может ссылаться на связь, заведённую тем же запросом.
Справка
Безопасность и блок «Личный сейф»
Vtorum проверяет доступ на сервере для каждой страницы, базы, записи, структуры DAG и файла. UUID объекта сам по себе не даёт доступа: запрос должен пройти проверку пространства, роли или явного постраничного grant.
Сессия хранится в защищённой HttpOnly cookie; изменяющие запросы проверяют Origin/Referer.
Сессия входа действует 30 дней с последнего визита, а не с момента входа: пока человек заходит хотя бы раз в месяц, срок сессии и cookie продлеваются (не чаще раза в сутки), и его не разлогинивает. Сессия, которой не пользовались 30 дней, закрывается, а кнопка «Выйти» закрывает её сразу.
Системный пользователь интеграции работает только в своём пространстве и только с узлами, к которым ему выдан доступ.
HTML, URL и файловые MIME проверяются сервером; исполняемые вложения выдаются только на скачивание.
Блок «Личный сейф»
Блок «Личный сейф» виден исключительно своему автору. Никакие права на страницу этого не меняют: ни соавтор с правом редактирования, ни владелец пространства, ни системный администратор, ни получатель выданного доступа чужой блок не увидят — он не доходит до них с сервера. Для всех, кроме автора, блока на странице просто нет.
Правило действует на каждом пути, которым содержимое покидает сервер: страница в редакторе и в режиме чтения, оффлайн-пакет, Developer API V2, поиск, контекст AI, тень объекта в другом пространстве, веб-публикация и её PDF. В публикации сейф не показывается никогда — у публичной страницы нет читателя-автора. Точечные запросы по идентификатору блока (аудит, ревизии, чтение и правка через API) для чужого сейфа отвечают «не найдено», поэтому знание идентификатора ничего не даёт.
Правка страницы другим пользователем блок не затрагивает: сервер игнорирует любые изменения и удаления чужого сейфа и сохраняет его на прежнем месте, даже если в сохранённом снимке страницы его нет — а его там нет всегда, ведь редактор его не получал. Удалить блок может только автор.
Открытый текст и ключевая фраза существуют только в локальном состоянии браузера. При нажатии «Зашифровать» браузер создаёт случайные salt и IV, выводит ключ через PBKDF2-SHA-256 и шифрует текст AES-256-GCM. В API передаётся только шифротекст и параметры контейнера.
Автором считается учётная запись, создавшая блок; сменить автора нельзя. Если такого пользователя удалить, блок останется в странице, но открыть его будет некому.
После скрытия вкладки, перехода со страницы или блокировки локальный plaintext очищается. Однако вредоносное расширение браузера, malware или уже исполняющийся скрипт того же origin теоретически могут прочитать текст, пока блок разблокирован.
Справка
Диагностика и устранение ошибок
/health — дешёвая проверка жизни API без обращения к зависимостям.
/ready с кэшированием проверяет PostgreSQL и объектное хранилище и возвращает 503 при недоступности.
/api/version возвращает установленную версию.
У задач импорта и AI сохраняются статус, прогресс и ошибка.
Для API сообщайте request_id из ответа.
При проблеме импорта скачайте «Отчёт JSON» из истории задачи. При проблеме массовой загрузки откройте «Настройки → Загрузки» и скопируйте точную ошибку элемента. Журнал AI прокручивается внутри собственной панели; для embedding-ошибок передавайте модель, endpoint, число ожидаемых и полученных векторов и безопасную техническую диагностику.