Перейти к содержанию

Передача Блокнота и сценарии восстановления

«Блокнот» теперь имеет полный прикладной путь: local notes, transactional outbox, стабильные операции, server revision, journal cursor, ручные конфликты, tombstones и экспорт. Последний урок превращает набор функций в передаваемый проект. Результат — регламент, по которому следующий разработчик понимает текущее состояние, ожидаемые переходы и задачи, которые ещё нужно выполнить в своей среде.

Архив содержит конечные файлы, а не архив выполненных экспериментов. Автор не запускал Node сервер, браузерные сценарии, тесты или синхронизацию устройств. Все ожидаемые состояния обозначены как not_run. Этот статус важен для передачи: наличие обработчика ошибки не подтверждает, что он уже сработал в конкретной версии браузера.

Передаём три независимых вида состояния

Исходники приложения описывают алгоритм, IndexedDB хранит работу определённого браузерного профиля, server data хранит канонические заметки и историю аккаунтов. Ни одна из этих частей не заменяет остальные. ZIP с кодом не содержит пользовательские заметки, а JSON export не является серверным ledger. При восстановлении сначала определяют, какой вид состояния был потерян.

В README перечислены функции файлов. Db.js содержит схему и локальные переходы, sync.js — сетевой проход и таймер, app.js — форму и действия пользователя, server.mjs — HTTP контракт. Страница и стили входят в public. Дополнительные npm пакеты не требуются; reader самостоятельно запускает Node.js 24 и открывает localhost:4174. Авторский запуск не подразумевается.

Версия браузерной схемы равна одному. Имя базы зависит от учебного аккаунта. Server state содержит journal и results без очистки, поэтому длительно отсутствовавшая копия ещё может продолжить по cursor и повторить opId. Для перехода к производственной СУБД нужно сохранить эти прикладные свойства, а не просто перенести файл в другой каталог.

Описываем сохранение и доставку отдельно

Первый сценарий передачи — новая заметка при отключённых запросах. После complete ожидается локальный объект и операция outbox. Перезагрузка уже загруженной сессии должна сохранить эти данные в пределах доступного хранилища. Затем восстановление запросов приводит к accepted и удалению конкретной операции. Сообщение о сети между этапами не должно объявлять потерю notes.

Второй сценарий — правка во время отправки. Сохранённый снимок остаётся неизменяем, notes получает большую localVersion. После accepted новая server revision связывается с текущим body, и создаётся следующий opId. Ожидаемая конечная редакция включает позднюю правку. Если итоговый текст откатился к первому снимку, проблему следует искать в подтверждении, а не устранять повторной загрузкой страницы.

Третий сценарий — потерянный ответ. Сервер мог сохранить accepted, а браузер сохранил outbox. Повтор той же операции должен вернуть прежний result без новой revision. Для этого server ledger и note изменение должны иметь согласованное хранение. Конечный JSON сервер показывает принцип, но не обещает durability после любой аварии носителя.

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

Условие Локально На сервере
Сохранение без запросов notes и queued вместе Может оставаться прежняя revision
Accepted неизменённого снимка outbox удалён, note каноническая Одна новая revision
Accepted при поздней правке Текущий body и новый opId Принят прежний снимок
Потерянный ответ Прежний opId остаётся Ledger может уже содержать accepted

Конфликт не является сетевым сбоем

Два независимых профиля одного аккаунта получают общую server revision, затем меняют документ отдельно. Второе намерение на устаревшей основе должно получить conflict. Notes сохраняет локальный текст, remote хранит каноническое состояние, outbox становится blocked. Такой результат нужен даже при быстром и устойчивом соединении: причина в двух редакциях, а не в качестве сети.

Регламент выбора предлагает два действия. Принять remote — удалить blocked операцию и сохранить канонический вариант без нового push. Подготовить своё объединение — сохранить форму локально, затем создать новый opId относительно прочитанной remote revision. Если сервер успел измениться ещё раз, повторный conflict допустим и должен сохранить подготовленный текст.

Удаление также участвует в этом сценарии. Tombstone передаётся как deleted true и новая revision, а старая офлайн-копия получает явное состояние удаления. Принять remote означает согласиться с ним; свой вариант может восстановить документ по правилам учебного сервера. Производственная политика необратимого удаления и ролей должна определяться дополнительно.

Локальные вкладки и независимые устройства

Для одной IndexedDB Web Locks разрешает только одному отправителю выполнять pass, а BroadcastChannel предлагает другим вкладкам перечитать список. Открытая форма защищена expectedVersion. Если другая вкладка уже изменила note, сохранение устаревшего экрана отменяется, поля остаются для копирования. Эти механизмы имеют разные функции и не должны заменяться одним общим флагом «занято».

Второй браузерный профиль использует другую IndexedDB и другую область Web Locks. Он согласуется через server revision и pull, а не через BroadcastChannel. Настоящий второй компьютер потребует доступного HTTPS сервера и действующей системы сессий. Архив не содержит такого размещения, поэтому передающий не должен утверждать, что реальные устройства уже соединены.

Без Web Locks серверная синхронизация отключена с пояснением. Локальное редактирование и экспорт остаются доступны. Для расширения совместимости понадобится отдельный алгоритм владения, проверенный в поддерживаемых браузерах. Скрытый fallback через неатомарный localStorage флаг дал бы ложную уверенность и мог бы оставить очередь навсегда остановленной после закрытия вкладки.

Восстановление начинается с доступного текста

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

При потере browser data согласованные записи можно снова получить с сервера, однако неотправленная работа исчезнет без экспорта. При потере server data старый cursor может получить 409. Это другая авария: client snapshot помогает сохранить текст, но не восстанавливает прежний ledger автоматически. Выбор нового server поколения и перенос документов должны быть осмысленными, без смешения старых revision.

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

Регламент теперь называет гарантии ровно на доступном уровне: локальная транзакция сохраняет связанный переход, стабильный opId закрывает потерянный ответ, revision выявляет конкурирующие правки, cursor продолжает журнал, экспорт удерживает доступное состояние. Оглавление курса связывает четырнадцать шагов, а README позволяет передать полный конечный пример с явным not_run и без обещания скрытой службы синхронизации.

Оглавление серии