Прошлый раз я писал про то, как заложил в схему БД поля под синхронизацию, которой пока нет. Синхронизации до сих пор нет, зато вышли два обновления: 0.2.0 и 0.2.1. В этой статье про три вещи, на которых пришлось подумать: переносимую папку с данными, бэкапы и импорт из Notion и Obsidian. Nookly — локальное приложение для заметок на Flutter: страницы, блоки, таблицы, канбан, поиск. Данные лежат в SQLite на устройстве, без облака.

Проблема: данные лежат где-то в системной директории

До 0.2.1 база, картинки и настройки жили там, куда их кладёт ОС для приложения: свой путь на Windows, свой на Linux. Для пользователя это означает, что вопрос «как перенести мои заметки на другой компьютер» не имеет простого ответа. Хочется, чтобы ответ звучал так: скопируй папку. Сейчас всё лежит в одной папке Nookly/: база, картинки, настройки, а рядом .backups/. Путь виден в настройках, папку можно открыть в проводнике или перенести. Если указать место, где уже есть база, приложение предложит открыть её, а не создавать новую поверх.

Почему просто скопировать data.db — не бэкап

Первая мысль для бэкапа: скопировать файл базы. С SQLite это работает хуже, чем кажется.

  • Если база в режиме WAL, свежие транзакции могут лежать не в основном файле, а в отдельном -wal. Копия одного .db потеряет последние записи.

  • Если копировать файл в момент записи, можно получить несогласованный снимок.

Для консистентной копии у SQLite есть штатные способы: backup API или команда VACUUM INTO:

VACUUM INTO '/path/to/backup.db';


Она создаёт самостоятельный, уже «сжатый» файл базы с согласованным состоянием, не требуя останавливать приложение.

backups
backups

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

А в браузере папки нет

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

Импорт из Notion и Obsidian

Главная причина не переезжать на новый инструмент — начинать с нуля. Поэтому в 0.2.0 появился импорт zip и Markdown: страницы, картинки и CSV-базы из Notion.

Экспорт Notion устроен так, что в имена файлов и папок добавляется длинный идентификатор, а ссылки между страницами — это относительные пути с URL-кодированием. Значит, чтобы перенести связи между страницами, недостаточно просто прочитать Markdown: нужно сопоставить пути из ссылок с импортированными страницами. У Obsidian всё проще: обычные .md и [[вики-ссылки]].

Форматирование внутри блока

В 0.2.1 в блоках появились жирный, курсив, подчёркивание, зачёркивание, код, цвет текста и фона, а также ссылки [[страница]], @, @дата и внешние.

rich-text
rich-text

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

Приложение: nookly.ru, репозиторий с релизами: GitHub, зеркало: GitFlic.