Files
Flora/PLAN.md
T
2026-08-16 23:32:12 +03:00

21 KiB
Raw Blame History

PLAN — Текстовый редактор/заметочник «Flora»

Минималистичный markdown-заметочник с git-историей, синхронизацией и графом связей. Аналог Obsidian, но лёгкий: быстрый запуск на любом железе, мгновенное открытие заметок.

Технологии

Компонент Решение
Язык C++17
UI Qt 6.8 LTS, Qt Quick / QML
Сборка CMake
Markdown-парсер cmark-gfm (CommonMark + GFM)
Git libgit2 (с поддержкой SSH через libssh2 + OpenSSL)
SSH libssh2 + OpenSSL (генерация ключей, known_hosts)
Подсветка кода KSyntaxHighlighting (KDE, LGPL — совместимо с GPL-3.0)
БД SQLite (Qt SQL) — метаданные, теги, связи, свойства
Diff libgit2 diff между blob версии и текущим файлом
PDF QtPdf (предпросмотр) + QPdfWriter (экспорт)
Лицензия GPL-3.0

Целевые платформы: macOS, Windows, Linux, Android.

Архитектура

Flora/
├── CMakeLists.txt, LICENSE (GPL-3.0), README, .gitignore
├── src/
│   ├── main.cpp
│   ├── app/  (VaultManager, WindowController)
│   ├── core/  (FileStore, TreeModel, DocumentManager, SettingsStore)
│   ├── git/GitManager.{h,cpp}          # libgit2
│   ├── markdown/ (MdParser@cmark-gfm, HtmlRenderer, SyntaxHighlight)
│   ├── db/Database.{h,cpp}             # SQLite: теги, связи, свойства
│   ├── editor/ (DiffRenderer)
│   ├── sync/ (SyncManager, WebDavSync, SyncthingClient, GitHubSync,
│   │          SshManager, ErrorCatalog)
│   └── export/ (HtmlExporter, PdfExporter)
├── qml/
│   ├── MainWindow.qml, VaultWindow.qml
│   ├── wizard/WelcomeWizard.qml, ProviderSetupGuide.qml, SshSetupGuide.qml
│   ├── panels/ FileTreePanel, TabsBar, EditorPanel, FormatToolbar,
│   │          CalendarPanel, LinksTagsPanel, GraphPanel, TableEditor
│   └── dialogs/ NameDialog, ConfirmDialog, HistoryDiffDialog, SyncDialog,
│               VaultSwitcherPopup
├── third_party/ cmark/ libgit2/ libssh2/ openssl/ ksyntaxhighlighting/
├── tests/  (QtTest + Catch2)
└── packaging/ (macOS / Windows / Linux / Android)

Функциональные требования (общие)

  • Левая панель (файловое дерево) — 15% экрана, ширина меняется мышью; центральная — 70%; правая — 15%. Размеры панелей запоминаются между сессиями.
  • Автосохранение файла каждые 5 секунд.
  • Хранилище = локальная папка, внутри которой git-репозиторий (создаётся автоматически).
  • Все сохранения — автоматически, авто-коммиты в git.
  • Редактор: режимы «редактирование» и «просмотр» (рендер как HTML в браузере).
  • Файлы любого формата открываются корректно: md — редактор, html/pdf — предпросмотр.

Фазы

Фаза 0 — Каркас

  1. Репозиторий, LICENSE (GPL-3.0), README, .gitignore.
  2. Подключение cmark, libgit2 (с SSH), libssh2, OpenSSL, KSyntaxHighlighting как подпроектов (статическая сборка).
  3. Скелет: главное меню вверху (Файл / Правка / Вид / Справка), SplitView 15/70/15, кнопка «+ хранилище» внизу слева.

Фаза 1 — Первый запуск (мастер)

  1. WelcomeWizard: выбор локальной папки (новая или с файлами) → предложение подключить GitHub/GitLab/Gitea, Nextcloud/WebDAV, Syncthing → git-репозиторий создаётся автоматически → открытие хранилища. Выбор запоминается.
  2. Подключение git-провайдера — два режима на выбор:
    • HTTPS + токен (через ProviderSetupGuide);
    • SSH-ключ (через SshSetupGuide) — если токен создать невозможно. Подключение можно пропустить; позже доступно через кнопку хранилища (внизу слева) → «Настройки хранилища» → «Подключить синхронизацию».

5.1. HTTPS + токен (ProviderSetupGuide)

Пошаговая инструкция для каждого провайдера:

  • Шаг 1 — создать токен: точная ссылка на страницу токенов и необходимые права:
    • GitHub: github.com/settings/tokens (Fine-grained: Contents: Read and write / классический scope repo);
    • GitLab: Настройки → Access Tokens (scope api или read_repository+write_repository);
    • Gitea: Настройки → Приложения → Personal Access Token (scope repo).
  • Шаг 2 — создать репозиторий (пустой, без README/.gitignore — иначе конфликт истории).
  • Шаг 3 — для self-hosted GitLab/Gitea: URL инстанса (включая http://localhost:3000), пометка про HTTPS.
  • Шаг 4 — вставить токен, кнопка «Проверить соединение» (реальный API-запрос: проверка токена и доступности репо), после успеха — авто-push и настройка автосинка.
  • Кнопки: «Скопировать команды для терминала» (git remote add/push вручную), «Назад/Пропустить».

5.2. SSH-ключ (SshSetupGuide)

  • Использовать существующий ключ (путь + опц. passphrase, хранится в системном keychain / настройках с предупреждением) ИЛИ сгенерировать новый в приложении (ed25519/RSA через OpenSSL, работает и на Android, без ssh-keygen).
  • Добавить публичный ключ в аккаунт: инструкция + кнопка «Скопировать публичный ключ»:
    • GitHub: Settings → SSH and GPG keys;
    • GitLab: Preferences → SSH Keys;
    • Gitea: Настройки → SSH-ключи.
  • Параметры: хост (github.com, gitlab.com, custom), порт (22/другой), имя пользователя (git по умолчанию), строка подключения вида git@github.com:user/repo.git.
  • «Проверить соединение»: реальное подключение через libssh2; проверка host key: при первом подключении показать отпечаток и предложить «Доверять и сохранить» (known_hosts в .flora/ssh/); при несовпадении — блокировка с предупреждением «Возможен MITM».
  • Успех → авто-push и настройка автосинка.

Фаза 2 — Мульти-хранилища (несколько окон)

  1. VaultManager: список известных хранилищ в настройках; последнее открытое = основное (открывается при старте).
  2. Кнопка внизу слева → поповер со списком хранилищ + «Добавить новое»: новое хранилище открывается в новом окне, старое продолжает работать; закрытие окна не удаляет хранилище; после перезапуска открывается только новое (основное), к старым — возврат через ту же кнопку.

Фаза 3 — Хранилище и файловое дерево

  1. FileStore + QFileSystemWatcher, TreeModel для QML TreeView: подпапки с отступами, стрелка «>» раскрытия, иконки пустой/заполненной папки и файлов по типу.
  2. Кнопка «+» над деревом и ПКМ по пустому месту → меню «Файл»/«Папка» → диалог имени. Переименование (F2/ПКМ), удаление (файл/пустая папка — одно подтверждение, непустая папка — двойное), перемещение drag&drop между папками.
  3. Двойной клик по файлу — открыть в новой вкладке (md — в редакторе, прочие — предпросмотром).

Фаза 4 — Редактор, вкладки, автосохранение

  1. DocumentManager: список открытых файлов, QTimer автосохранения каждые 5 сек (только если есть изменения), восстановление открытых вкладок после перезапуска.
  2. TabsBar с вкладками, закрытием, режимом «открыть рядом»: центральная область — две колонки SplitView, в каждую открывается вкладка (одна активна в каждой колонке).
  3. Режим редактирования: TextArea + моноширинный шрифт, путь/название файла в заголовке вкладки. Переключение режимов — Ctrl+E / Ctrl+V.

Фаза 5 — Панель форматирования (подменю вверху)

  1. FormatToolbar над редактором, видна в режиме редактирования:
    • Жирный, курсив, подчёркнутый, зачёркнутый, выделение (==mark==), цвет текста, цвет выделения (палитры), верхний/нижний индекс (возведение в квадрат, подстрочное);
    • Заголовки # 1–6 (выпадающий выбор);
    • Списки: маркированный / нумерованный / задачи - [ ];
    • Цитата (>), Выноска (GFM > [!NOTE/INFO/WARN/ERROR]);
    • Таблица: по умолчанию 2×1; в режиме редактирования таблицы по краям «+»-кнопки справа и снизу (20px шириной), добавляют столбец/строку, раскладка растёт по вертикали/горизонтали;
    • Обтекание текста вокруг картинок и таблиц: вставка директивы ![[img.png|float:left|width:40%]], рендер в обтекаемый блок. Кнопки работают с выделенным текстом (вставка/оборачивание markdown-разметки).

Фаза 6 — Просмотр Markdown

  1. MdParser на cmark-gfm: CommonMark + GFM-таблицы, зачёркивание, автоссылки, выноски, raw-HTML, wiki-ссылки, директивы обтекания.
  2. Подсветка кода: KSyntaxHighlighting — язык из ограждения (таблица алиасов: «С», «C», «С++», «C++», python, go, rust, js, …; при отсутствии — авто по расширению/дефолт). Подсветка в режиме просмотра; в редакторе — по расширению файла через слоёный Text (фоновый слой rich-текст + прозрачный TextArea сверху), обновление по таймеру-дебонсу.
  3. Задачи: - [ ]/- [x] рендерятся чекбоксами; клик в просмотре переключает галочку в исходнике и перерисовывает.
  4. Ссылки в просмотре: клик по wiki/обычной ссылке открывает файл в новой вкладке.

Фаза 7 — Правая панель: календарь, ссылки и теги, граф

  1. Календарь: клик по дню создаёт/открывает Журнал/ГГГГ-ММ-ДД.md (папка журнала настраивается).
  2. «Ссылки и теги» (секция над графом, для текущего файла): все ссылки и теги файла; клик по ссылке → переход в файл; клик по тегу → список всех файлов с этим тегом, клик по файлу → открыть.
  3. Граф связей (Canvas): узлы-файлы и теги-кластеры, рёбра по ссылкам/тегам/связям из БД, простая симуляция отталкивания/притяжения на JS, drag узлов, клик — открыть файл, кнопка «Обновить».

Фаза 8 — База данных (notion-подобные связи)

  1. Database (SQLite, файл .flora/flora.db в хранилище): таблицы files, tags, file_tags, links, properties (свойства страниц: приоритет, статус, даты, связи), relations (родитель/ребёнок).
  2. Синхронизация БД с файловой системой при каждом изменении. UI: диалог «Свойства и связи» файла (ПКМ → Свойства), поиск по свойствам, backlinks. Граф дополнительно рисует связи из БД.

Фаза 9 — Git: история и откат

  1. GitManager: репозиторий создаётся автоматически при создании хранилища, авто-коммиты, .gitignore (.flora/, .stfolder, конфликт-копии).
  2. Меню Правка → «Вернуться к предыдущей версии»: для открытого файла список версий → diff-просмотр (строки «+»/«−» цветные, контекст), внизу кнопки «Применить» и «Отклонить». Применение — замена файла на выбранную версию (через git) + автокоммит отката.

Фаза 10 — Экспорт и предпросмотр

  1. Меню Файл → Экспорт: HTML (картинки инлайн base64 или копией, с обтеканием) и PDF (HTML → QTextDocument → QPdfWriter).
  2. Предпросмотр .html (тот же QTextDocument-рендер, без JS) и .pdf (QtPdf) из дерева.

Фаза 11 — Синхронизация

  1. SyncManager (период в настройках):
    • Nextcloud/WebDAV: загрузка/скачивание дерева, сравнение mtime+hash, конфликты → имя.conflict.время.md, авторизация по логину/паролю (сохранение токена);
    • GitHub/GitLab/Gitea: git push/pull по HTTPS (токен) или SSH, merge конфликтов;
    • Syncthing: REST API (localhost:8384): сканирование папки, статус устройств, кнопка «Синхронизировать». Файлы .stfolder игнорируются git-ом. Подключение новых провайдеров — через кнопку хранилища (внизу слева) → «Настройки хранилища».

Каталог ошибок (ErrorCatalog)

Каждой ошибке API/libgit2/SSH соответствует человеческое сообщение и рекомендация:

Ошибка Причина Что показать пользователю
401 Unauthorized Неверный/просроченный/отозванный токен «Токен не принят. Создайте новый» + ссылка на страницу токенов
403 Forbidden Недостаточно прав токена / rate limit «Проверьте права токена (scope repo/api)»; при rate limit — «Подождите N минут»
404 Not Found Неверный URL инстанса или репо не существует / нет доступа (private) «Проверьте адрес и что репозиторий создан», кнопка «Создать пустой репозиторий» (шаг 2)
409 / non-fast-forward В репозитории уже есть чужие коммиты «Отключите «Синхронизировать» и выполните ручное слияние» + команды терминала
TLS/SSL (self-signed) Self-hosted инстанс без сертификата «Добавьте сертификат в доверенные» / опция «Разрешить небезопасное соединение» с предупреждением
Таймаут / нет сети Недоступен хост, прокси, DNS «Проверьте интернет и прокси», повтор с ретраями
Двухфакторка GitHub требует OTP при пароле «Используйте токен вместо пароля»
Пустой локальный репо Хранилище ещё без коммитов Авто-коммит инициализационный перед push
Permission denied (publickey) (SSH) Ключ не добавлен в аккаунт / не тот ключ «Добавьте публичный ключ в аккаунт» + ссылка на страницу ключей
Passphrase неверна (SSH) Неверная парольная фраза «Введите passphrase заново»
Host key mismatch (SSH) Сервер подменился / ключ поменялся «Подключение заблокировано: отпечаток изменился» + оба отпечатка, кнопка «Удалить старый и продолжить» (с предупреждением)
Таймаут/отказ порта (SSH) Неверный порт/хост, файрвол, репо не существует «Проверьте хост, порт и имя репозитория»
Неверный формат ключа (SSH) Ключ повреждён/не тот формат «Поддерживаются ed25519, RSA (PKCS#1/PKCS#8)»

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

Фаза 12 — Настройки

  1. QSettings: размеры панелей (запоминание), шрифты, интервалы автосохранения/автокоммита, тема (светлая/тёмная), токены, основное хранилище. Горячие клавиши.

Фаза 13 — Тесты

  1. QtTest/Catch2: md→HTML (таблицы, выноски, обтекание, задачи), подсветка языков (алиасы), GitManager (коммиты, откат, diff), Database, конфликты синка. Прогон через CTest.

Фаза 14 — Android

  1. Сборка cmark/libgit2/libssh2/OpenSSL/KSyntaxHighlighting под NDK (статически; libgit2 с SSH-транспортом). Манифест, разрешения, выбор хранилища системным диалогом, ПКМ → долгое нажатие, адаптация панелей под экран телефона. SSH-ключи — в приватном хранилище приложения.

Фаза 15 — Упаковка и лицензия

  1. Пакеты: macOS .app/.dmg, Windows NSIS, Linux AppImage, Android APK.
  2. Лицензионные заголовки GPL-3.0 во всех файлах, README, чек-лист соответствия лицензии.

Служебные файлы проекта

  • PLAN.md — этот план (актуальная версия).
  • CHANGELOG.md — история изменений проекта.
  • done.md — журнал итераций: что планировалось за итерацию и что сделано.