Раньше в рабочем пространстве Notez был ровно один человек. С v0.3.0 их может быть несколько: пригласите кого-то по email, и общими станут заметки, теги, доски и ИИ-чат, который видит всё это.
Интереснее то, чего я делать не стал.
Функция, о которой спрашивают первой
«Могут ли два человека одновременно редактировать одну заметку?»
Как в Google Docs — два курсора в одном абзаце, символы вперемешку по мере набора — нет. Это трудная задача, и решить её как следует — значит взять CRDT или операционные преобразования, держать постоянное соединение на каждый открытый документ и переписать хранение заметки: уже не документ, а поток операций, который проигрывается заново.
Функция хорошая. Но это почти отдельный продукт, и она задержала бы совместный доступ на месяцы ради случая, который для приложения заметок редок. Люди обычно не пишут один и тот же абзац одновременно. Они пишут разные заметки или одну заметку в разное время.
Поэтому я делал совместный доступ под то, что происходит на деле, а редкий случай сделал безопасным, пусть и не гладким.
Что происходит на деле
Три вещи, от менее важной к главной.
Вы хотите знать, что здесь есть кто-то ещё. Откройте заметку, которая сейчас открыта у коллеги, и рядом со статусом сохранения появится его аватар. Он обновляется каждые несколько секунд и исчезает примерно через минуту после того, как коллега закроет заметку.
Это намеренно индикатор присутствия, а не «печатает…». Он отвечает на вопрос «есть ли здесь сейчас кто-то ещё?» — тот, после которого вы либо ждёте, либо продолжаете. Устроено это как хеш в Redis на каждую заметку с TTL 60 секунд и периодический опрос: без WebSocket и без рассылки по подпискам. Вся функция — несколько десятков строк, и если Redis ненадолго недоступен, заметка всё равно открывается и сохраняется.
Вы хотите знать, кто что-то изменил. Если последнюю правку сделали не вы, в статусе сохранения теперь написано Изменено: Саша, 4 минуты назад, а если вы — просто время. Вместе с 30 днями истории версий, которые уже хранит каждая заметка, это даёт ответ на вопрос «как это выглядело до правок Саши?».
Авторство правок оказалось тем, чего люди больше всего хотели от совместной работы, а стоит оно два столбца в базе.
Вы не хотите терять работу. Это главное.
Отказ в записи
Наивный совместный доступ ломается тихо и полностью: вы открываете заметку, десять минут правите, сохраняете, и ваша версия заменяет ту, что коллега сохранил восемь минут назад. Никаких ошибок. Его работа просто пропала, и никто из вас не узнает об этом, пока кто-нибудь на следующей неделе не заметит, что не хватает абзаца.
Теперь у каждой заметки в Notez есть номер версии. Загружая заметку, редактор запоминает версию, которую увидел, и каждое сохранение отправляет этот номер обратно. Обновление выполняется так:
UPDATE "Note" SET ... WHERE id = $1 AND "contentVersion" = $2
Если кто-то за это время сохранил заметку, версия уже не совпадает, условию WHERE соответствует ноль строк, и запись не происходит. Вы видите баннер с именем того, кто изменил заметку, и кнопку Перезагрузить.
Важная деталь: проверка стоит в условии WHERE, а не в if перед ним. У схемы «проверить, потом записать» есть окно между проверкой и записью. Оно маленькое, но два сохранения в один и тот же момент — ровно тот случай, когда защита должна сработать. Если версия входит в условие обновления, решает база данных, атомарно, и второй автор проигрывает.
Проиграть — правильный исход. Альтернатива отказу — угадывать, как совместить две версии абзаца, а неверная догадка хуже честной ошибки, потому что неверная догадка выглядит так, будто всё сработало.
Чего я намеренно не стал делать
Нет прав доступа на уровне заметки. Доступ выдаётся на рабочее пространство. Каждый приглашённый читает в нём всё, включая корзину. Права на каждую заметку — это проверка прав на каждом пути чтения, интерфейс для управления ими и поток вопросов в поддержку от людей, которые не понимают, почему не видят заметку. Если нужна граница, создайте второе рабочее пространство: они бесплатные и полностью изолированы.
Нет комментариев. Ветка комментариев — это маленькая социальная сеть. Не сейчас.
Нет курсоров в реальном времени. Причины — выше.
Нет оплаты за места. Участникам не нужен свой план. Места берутся из плана владельца: 3 на Free, 10 на Pro, 25 на Ultra, а всё, что хранится в рабочем пространстве, идёт в лимит владельца.
Где проходит граница
Совместный доступ выдаётся на рабочее пространство, а рабочие пространства и раньше были в Notez границей изоляции: ИИ-чат видит только текущее, ключ MCP привязан к одному. При совместном доступе это свойство сохраняется: пригласите коллегу в Работу, и из Личного он не получит ничего — ни в поиске, ни через ИИ, ни через ключ.
Это проверяется на сервере при каждом запросе, и именно поэтому я выбрал единицей совместного доступа рабочее пространство, а не придумал новую.
Если вы держали всё в одном рабочем пространстве, а теперь хотите поделиться частью, сначала перенесите эти заметки в отдельное пространство, потом приглашайте.
Подробности — в статье Как поделиться рабочим пространством с другими людьми. Всё, что вошло в релиз: v0.3.0.
Читайте также
Исполнитель, который здесь больше не работает — почему при удалении человека из рабочего пространства его назначения снимаются, а не остаются серым именем на сорока заметках.
Четыре способа вернуть потерянное: отмена, версии, корзина и защита от перезаписи — что возвращают отмена, 30 дней истории версий, корзина и защита от конфликта сохранений и где заканчивается каждый из этих механизмов.
Notez: приложение для заметок, созданное для разработчиков — что такое Notez, какими путями в него попадают заметки и что входит в каждый план.