From bfb962ab7ec966ffab5836c049d437b9d0800209 Mon Sep 17 00:00:00 2001 From: "Flora (opencode)" Date: Sun, 16 Aug 2026 23:32:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=82=D0=B5=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=200:=20=D0=BF=D0=BB=D0=B0=D0=BD,=20=D0=B6=D1=83=D1=80?= =?UTF-8?q?=D0=BD=D0=B0=D0=BB=D1=8B,=20gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 22 +++++ CHANGELOG.md | 13 +++ PLAN.md | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++ done.md | 30 +++++++ 4 files changed, 304 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 PLAN.md create mode 100644 done.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3557f33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Сборка +build/ +build-*/ +cmake-build-*/ + +# IDE +.idea/ +.vscode/ +*.user +*.autosave + +# Qt +.qmlcache/ +*.qmlc +*.jsc + +# OS +.DS_Store +Thumbs.db + +# Служебные артефакты +*.log \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9f00f00 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# CHANGELOG + +Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.0.0/). +Версия проекта: `0.0.0` (разработка не начата). + +## [0.0.0] - 2026-08-16 + +### Добавлено +- Составлен полный план разработки (PLAN.md): архитектура, технологический стек + (Qt 6.8 QML, libgit2 + libssh2, cmark-gfm, KSyntaxHighlighting, SQLite), 16 фаз. +- Заведён журнал итераций (done.md). +- Инициализирован локальный git-репозиторий проекта (удалённый Gitea-репозиторий + будет добавлен позже). diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 0000000..19bf68c --- /dev/null +++ b/PLAN.md @@ -0,0 +1,239 @@ +# 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 — Первый запуск (мастер) +4. WelcomeWizard: выбор локальной папки (новая или с файлами) → предложение подключить + GitHub/GitLab/Gitea, Nextcloud/WebDAV, Syncthing → git-репозиторий создаётся + автоматически → открытие хранилища. Выбор запоминается. +5. Подключение 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 — Мульти-хранилища (несколько окон) +6. VaultManager: список известных хранилищ в настройках; последнее открытое = основное + (открывается при старте). +7. Кнопка внизу слева → поповер со списком хранилищ + «Добавить новое»: новое хранилище + открывается в новом окне, старое продолжает работать; закрытие окна не удаляет + хранилище; после перезапуска открывается только новое (основное), к старым — возврат + через ту же кнопку. + +### Фаза 3 — Хранилище и файловое дерево +8. FileStore + QFileSystemWatcher, TreeModel для QML TreeView: подпапки с отступами, + стрелка «>» раскрытия, иконки пустой/заполненной папки и файлов по типу. +9. Кнопка «+» над деревом и ПКМ по пустому месту → меню «Файл»/«Папка» → диалог имени. + Переименование (F2/ПКМ), удаление (файл/пустая папка — одно подтверждение, непустая + папка — двойное), перемещение drag&drop между папками. +10. Двойной клик по файлу — открыть в новой вкладке (md — в редакторе, прочие — предпросмотром). + +### Фаза 4 — Редактор, вкладки, автосохранение +11. DocumentManager: список открытых файлов, QTimer автосохранения каждые 5 сек + (только если есть изменения), восстановление открытых вкладок после перезапуска. +12. TabsBar с вкладками, закрытием, режимом «открыть рядом»: центральная область — две + колонки SplitView, в каждую открывается вкладка (одна активна в каждой колонке). +13. Режим редактирования: TextArea + моноширинный шрифт, путь/название файла в заголовке + вкладки. Переключение режимов — Ctrl+E / Ctrl+V. + +### Фаза 5 — Панель форматирования (подменю вверху) +14. FormatToolbar над редактором, видна в режиме редактирования: + - Жирный, курсив, подчёркнутый, зачёркнутый, выделение (==mark==), цвет текста, + цвет выделения (палитры), верхний/нижний индекс (возведение в квадрат, подстрочное); + - Заголовки # 1–6 (выпадающий выбор); + - Списки: маркированный / нумерованный / задачи `- [ ]`; + - Цитата (`>`), Выноска (GFM `> [!NOTE/INFO/WARN/ERROR]`); + - Таблица: по умолчанию 2×1; в режиме редактирования таблицы по краям «+»-кнопки + справа и снизу (20px шириной), добавляют столбец/строку, раскладка растёт + по вертикали/горизонтали; + - Обтекание текста вокруг картинок и таблиц: вставка директивы + `![[img.png|float:left|width:40%]]`, рендер в обтекаемый блок. + Кнопки работают с выделенным текстом (вставка/оборачивание markdown-разметки). + +### Фаза 6 — Просмотр Markdown +15. MdParser на cmark-gfm: CommonMark + GFM-таблицы, зачёркивание, автоссылки, выноски, + raw-HTML, [[wiki-ссылки]], директивы обтекания. +16. Подсветка кода: KSyntaxHighlighting — язык из ограждения (таблица алиасов: «С», «C», + «С++», «C++», python, go, rust, js, …; при отсутствии — авто по расширению/дефолт). + Подсветка в режиме просмотра; в редакторе — по расширению файла через слоёный Text + (фоновый слой rich-текст + прозрачный TextArea сверху), обновление по таймеру-дебонсу. +17. Задачи: `- [ ]`/`- [x]` рендерятся чекбоксами; клик в просмотре переключает галочку + в исходнике и перерисовывает. +18. Ссылки в просмотре: клик по [[wiki]]/обычной ссылке открывает файл в новой вкладке. + +### Фаза 7 — Правая панель: календарь, ссылки и теги, граф +19. Календарь: клик по дню создаёт/открывает Журнал/ГГГГ-ММ-ДД.md (папка журнала настраивается). +20. «Ссылки и теги» (секция над графом, для текущего файла): все ссылки и теги файла; + клик по ссылке → переход в файл; клик по тегу → список всех файлов с этим тегом, + клик по файлу → открыть. +21. Граф связей (Canvas): узлы-файлы и теги-кластеры, рёбра по ссылкам/тегам/связям из БД, + простая симуляция отталкивания/притяжения на JS, drag узлов, клик — открыть файл, + кнопка «Обновить». + +### Фаза 8 — База данных (notion-подобные связи) +22. Database (SQLite, файл `.flora/flora.db` в хранилище): таблицы files, tags, file_tags, + links, properties (свойства страниц: приоритет, статус, даты, связи), relations + (родитель/ребёнок). +23. Синхронизация БД с файловой системой при каждом изменении. UI: диалог + «Свойства и связи» файла (ПКМ → Свойства), поиск по свойствам, backlinks. + Граф дополнительно рисует связи из БД. + +### Фаза 9 — Git: история и откат +24. GitManager: репозиторий создаётся автоматически при создании хранилища, авто-коммиты, + .gitignore (.flora/, .stfolder, конфликт-копии). +25. Меню Правка → «Вернуться к предыдущей версии»: для открытого файла список версий → + diff-просмотр (строки «+»/«−» цветные, контекст), внизу кнопки «Применить» и «Отклонить». + Применение — замена файла на выбранную версию (через git) + автокоммит отката. + +### Фаза 10 — Экспорт и предпросмотр +26. Меню Файл → Экспорт: HTML (картинки инлайн base64 или копией, с обтеканием) + и PDF (HTML → QTextDocument → QPdfWriter). +27. Предпросмотр .html (тот же QTextDocument-рендер, без JS) и .pdf (QtPdf) из дерева. + +### Фаза 11 — Синхронизация +28. 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 — Настройки +29. QSettings: размеры панелей (запоминание), шрифты, интервалы автосохранения/автокоммита, + тема (светлая/тёмная), токены, основное хранилище. Горячие клавиши. + +### Фаза 13 — Тесты +30. QtTest/Catch2: md→HTML (таблицы, выноски, обтекание, задачи), подсветка языков + (алиасы), GitManager (коммиты, откат, diff), Database, конфликты синка. Прогон через CTest. + +### Фаза 14 — Android +31. Сборка cmark/libgit2/libssh2/OpenSSL/KSyntaxHighlighting под NDK (статически; libgit2 + с SSH-транспортом). Манифест, разрешения, выбор хранилища системным диалогом, + ПКМ → долгое нажатие, адаптация панелей под экран телефона. SSH-ключи — в приватном + хранилище приложения. + +### Фаза 15 — Упаковка и лицензия +32. Пакеты: macOS .app/.dmg, Windows NSIS, Linux AppImage, Android APK. +33. Лицензионные заголовки GPL-3.0 во всех файлах, README, чек-лист соответствия лицензии. + +## Служебные файлы проекта +- PLAN.md — этот план (актуальная версия). +- CHANGELOG.md — история изменений проекта. +- done.md — журнал итераций: что планировалось за итерацию и что сделано. diff --git a/done.md b/done.md new file mode 100644 index 0000000..27ff32a --- /dev/null +++ b/done.md @@ -0,0 +1,30 @@ +# done.md — журнал итераций + +Каждая итерация: что запланировано → что сделано. Сделанное помечается `[x]`, +к незавершённому возвращаемся в следующей итерации. + +## Итерация 0 — подготовка проекта + +**Планировалось:** +- [x] Составить подробный план разработки (PLAN.md) со всеми требованиями + и дополнениями (SSH, мастер первого запуска, notion-БД, тулбар и т.д.). +- [x] Создать CHANGELOG.md для истории изменений. +- [x] Создать done.md (этот файл) для журнала итераций. +- [x] Создать .gitignore. +- [x] Инициализировать локальный git-репозиторий и сделать первый коммит + (удалённый Gitea-репозиторий пользователь добавит позже). + +**Сделано:** +- PLAN.md создан (16 фаз, полная архитектура). +- CHANGELOG.md создан с записью 0.0.0. +- done.md создан. +- .gitignore создан. +- git init выполнен, первый коммит сделан. + +**Незавершённое / следующая итерация:** +- Итерация 1: Фаза 0 плана — каркас проекта: + - LICENSE (GPL-3.0), README; + - подключение cmark, libgit2 (SSH), libssh2, OpenSSL, KSyntaxHighlighting + как подпроектов (статическая сборка); + - скелет приложения: главное меню (Файл/Правка/Вид/Справка), SplitView 15/70/15, + кнопка «+ хранилище» внизу слева.