Разработка и безопасность CMS

Два редактора меняют одну запись CMS: как предотвратить перезапись изменений

Как предотвратить конфликт редактирования в CMS: проверка версии, понятное сообщение об ошибке и восстановление несохранённого текста.

Два редактора меняют одну запись CMS: как предотвратить перезапись изменений

Конфликт редактирования в CMS безопасно решается проверкой версии записи в момент сохранения и остановкой изменений, основанных на устаревшей копии. При этом редактор должен видеть правки коллеги и иметь возможность восстановить свою работу. Само уведомление о том, что запись открыл кто-то ещё, не защищает от перезаписи.

Представим команду контента, которая за один день уточняет описание услуги. Один редактор исправляет ценовые условия, другой дополняет заголовок в той же записи. Оба работают внимательно, но у второго открыта старая копия. После его сохранения ценовые условия возвращаются к прежней редакции. Интерфейс сообщает об успешном сохранении, поэтому ошибку замечают лишь после публикации.

Проблема в контракте сохранения между браузером и сервером. Её можно проверить воспроизводимым сценарием, а не предположениями о внимательности редакторов. Эта статья помогает подготовить такой тест и требования приёмки для улучшения существующей или индивидуально разработанной CMS.

Где исчезает исправление коллеги

При открытии записи браузер получает её содержимое. Пока человек пишет, на сервере может появиться более новая версия. Если браузер затем отправляет всю исходную запись со своими изменениями, сервер должен отличить актуальную правку от возврата старой копии.

Показа даты обновления недостаточно. Дата может быть лишь справочной, а сохранение по-прежнему принимать любое присланное содержимое. Вопрос разработчику конкретен: отказывает ли сервер в записи устаревшей версии, даже если интерфейс пользователя не выполнил проверку?

Конфликт возможен и между вкладками одного человека. Другим источником записи может быть импорт, интеграция или автоматическое обновление данных. Если защита работает только между видимыми пользователями CMS, в другом пути сохранения она может отсутствовать. В проверку нужно включить все пути, меняющие соответствующую запись.

Сначала договоритесь и о защищаемой единице. Это может быть вся страница контента, отдельная языковая версия или определённый блок данных. Слишком крупная единица создаёт лишние конфликты. Слишком мелкая позволяет соединить несовместимые поля, например цену и условие её вступления в силу.

Проверка версии в момент сохранения

HTTP предоставляет условное сохранение через If-Match. Клиент отправляет ранее полученный ETag, а сервер проверяет его соответствие текущему представлению. Если условие не выполнено, типичный ответ — 412 Precondition Failed. Механизм и требование строгого сравнения описаны в документации MDN по If-Match.

CMS может использовать и собственное поле версии, если оно обеспечивает равноценную безопасную логику сохранения. Важен результат: между проверкой и изменением не должно оставаться возможности для другого запроса незаметно перезаписать запись. Конкретный механизм базы данных или приложения разработчик выбирает с учётом существующей системы.

ETag идентифицирует версию представления, а не человека или разрешение доступа. Аутентификация и проверка прав по-прежнему нужны отдельно. Расчёт маркера версии тоже должен соответствовать сохраняемым данным. Если он не отражает изменения защищённых полей, сравнение не предотвратит соответствующий конфликт. См. пояснение MDN об ETag.

Нельзя заменять проверку конкретной версии общим условием существования записи. Например, If-Match: * не доказывает, что редактор работал с текущим содержимым. Проверка только в браузере также не гарантирует безопасность серверного сохранения. Оценку условий до выполнения метода определяет спецификация семантики HTTP.

Предупреждение, блокировка или совместное редактирование

Предупреждение о другом редакторе полезно для координации. Оно помогает решить, начинать ли работу сейчас. Однако сессия коллеги может завершиться некорректно или связь может прерваться. Индикатор присутствия не должен становиться единственной защитой данных.

Эксклюзивная блокировка может подходить для короткой ответственной правки, которую одновременно вправе делать один человек. Тогда нужно определить срок блокировки, её продление активной сессией и право перенять зависшую работу. После потери блокировки старая сессия не должна продолжать сохранение так, будто остаётся единственной.

Оптимистическая блокировка позволяет работать параллельно и проверяет конфликт при сохранении. Она подходит, если конфликты не постоянны, а интерфейс помогает их разрешать. Если команда ежедневно пишет одновременно в одном тексте, может быть обосновано совместное редактирование. Его внедрение — более широкая задача, чем простое окно предупреждения.

Выбирайте по характеру работы. Редакторы обычно меняют независимые поля? Им нужно совместно работать над предложением в реальном времени? Насколько опасно ошибочно соединить цену и описание? Необязательно внедрять самый сложный режим, если безопасность обеспечивают понятная проверка версии и разрешение конфликта.

Что показать человеку при конфликте

Сообщение должно сказать, что работа не сохранена, почему это произошло и что делать дальше. Например: «Запись изменилась с момента открытия. Ваш текст сохранён как локальная рабочая копия. Сравните изменения перед повторным сохранением». Обещать локальную копию можно только тогда, когда она действительно безопасно создана.

Для сравнения полезны исходная, текущая и собственная версия редактора. Если показывать только две последние, человеку бывает трудно определить, какие различия внесены им, а какие коллегой. Выделяйте конкретные поля, а не заставляйте перечитывать всю страницу без ориентиров.

Независимые изменения разных полей иногда можно объединять автоматически. Но название поля — не единственная мера связи. Название товара, изображение и спецификация могут описывать один комплект. Определяйте правила безопасного объединения по смыслу содержания, оставляя решение человеку в неоднозначных случаях.

С кнопкой «Перезаписать всё» нужна особая осторожность. Если такое действие вообще необходимо, покажите, какую текущую версию оно заменит, и сохраните восстанавливаемую историю. Пока шло сравнение, на сервере могла появиться ещё одна правка. Для сохранения объединённой версии нужна новая проверка актуальности.

Матрица сценариев для двух редакторов

Ниже предложен образец приёмочной проверки. Он не описывает готовые функции конкретной CMS. Используйте тестовую запись и две независимые сессии, чтобы сама проверка не меняла опубликованную информацию компании.

Сценарий

Проверка

Приемлемый результат

Оба меняют один заголовок

Второй сохраняет старую копию

Нет незаметной перезаписи, конфликт виден

Изменены разные поля

Проверена взаимосвязь полей

Безопасное объединение или обоснованное решение человека

Вкладка открыта долго

За это время коллега меняет запись

Старая вкладка не обходит проверку версии

Работает автосохранение

Конфликт возникает без нажатия кнопки

Видно несохранённое состояние, локальная работа не теряется

Пропадает соединение

Исход запроса неизвестен

После восстановления связи проверено состояние сервера

Запись меняет интеграция

Редактор продолжает со старой версии

Действует та же защита от конфликтов

Для каждого теста запишите последовательность сессий, исходную версию, отправленное действие и результат сервера. Снимок предупреждения полезен, но не доказывает отсутствие перезаписи в базе данных. После обновления проверьте и фактически сохранённое содержимое и историю.

Автосохранение не должно скрывать ошибку

Редактору нужно различать локальный ввод, отправку, подтверждённое сервером сохранение и конфликт. Если все ситуации обозначены одной галочкой, человек не знает, можно ли закрыть вкладку. Краткий текст состояния часто полезнее малозаметной анимации.

Запросы автосохранения могут перекрываться. Поздний ответ на старый запрос не должен перезаписывать в интерфейсе статус более новой работы. В тестах разработки искусственно задерживайте ответы и проверяйте обратный порядок получения. Так можно найти ошибку, незаметную на быстром офисном соединении.

После timeout нельзя автоматически считать, что сохранение не состоялось. Сервер мог выполнить действие, хотя браузер не получил ответа. Сначала нужно узнать актуальную версию и оценить сохранённый результат. Слепая повторная отправка старого запроса — небезопасная стратегия восстановления.

Как восстановить несохранённый текст

Локальная рабочая копия должна быть связана с конкретной записью, пользователем и исходной серверной версией. При восстановлении интерфейс может предложить сравнение вместо немедленной отправки на сервер. Предусмотрите удаление и политику хранения копии, особенно на общих устройствах или при работе с чувствительной информацией.

Полагаться только на предупреждение об уходе со страницы нельзя. MDN указывает, что событие beforeunload срабатывает ненадёжно в некоторых ситуациях, например при определённых последовательностях мобильного использования. См. ограничения события ухода со страницы. Сохранение работы нужно проектировать на протяжении всего редактирования.

Проверьте восстановление в реальных условиях команды: потеря соединения, окончание сессии и повторное открытие браузера. Сообщение «Работа восстановлена» не должно означать лишь загрузку старой серверной копии. Человек должен видеть, какие его изменения восстановлены, а какие ещё не сохранены.

Что требовать при приёмке улучшения CMS

Договоритесь о наблюдаемом результате: старая версия не может незаметно перезаписать новую, сообщение о конфликте сохраняет работу, а восстановление не обходит проверку актуальности. Проверка должна работать и при задержанных ответах, и при изменениях интеграции. Команде нужна краткая инструкция по выбору и объединению редакций.

Достаточно ли истории версий?

История помогает восстановить уже потерянное содержание, если нужная версия сохранена. Контроль конфликтов предотвращает незаметную ошибку в момент сохранения. У механизмов разные роли, и история не отменяет необходимости ясно сообщать человеку о конфликте.

Требует ли эта проблема новой CMS?

Не всегда. Сначала нужно изучить существующий путь сохранения, версии данных и возможности интерфейса. Возможно, достаточно локального улучшения. Если система не позволяет одинаково защитить все пути записи, нужно оценить более широкие изменения с конкретным обоснованием риска.

Если в команде пропадают правки, подготовьте один воспроизводимый сценарий и ожидаемый результат. По нему можно оценить объём разработки индивидуальной CMS или улучшения существующей системы. Структуру полей отдельно объясняет модель контента CMS, а выпуски программного обеспечения — материал о тестовой среде staging и плане rollback.