From 537e8a126e959c68779e140ae8a64998252c6cd6 Mon Sep 17 00:00:00 2001 From: mirivlad Date: Sun, 31 May 2026 12:10:58 +0800 Subject: [PATCH] plan: rewrite for Wails GUI + full file/folder workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Archive browser prototype as legacy (step 6) - New steps 11-14: Wails GUI, Files/Folders, D&D, stabilization - Steps 15+ paused until step 14 complete - DokuWiki moved to contrib/plugins/ (optional) - Full architecture: Wails bindings → Go core → vault+SQLite - Detailed acceptance criteria for each step --- docs/PLAN.md | 566 +++++++++++++++++++++------------------------------ 1 file changed, 230 insertions(+), 336 deletions(-) diff --git a/docs/PLAN.md b/docs/PLAN.md index 7dcaf24..8aa84a5 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -1,4 +1,4 @@ -# Верстак — Пошаговый план реализации +# Верстак — Пошаговый план разработки ## Принципы работы @@ -16,359 +16,246 @@ | 3 | Nodes Repository + CRUD + CLI Node | ✅ выполнен | | 4 | Vault Files: Trash + File Service + CLI File | ✅ выполнен | | 5 | Markdown Notes: Create/Read/Save + CLI Note | ✅ выполнен | -| 6 | Wails GUI MVP: Sidebar + Main Panel | ✅ выполнен (Go HTTP SPA) | -| 7 | Actions: Run URL/File/Command + GUI Tab | ✅ выполнен | -| 8 | Worklog: Entries + Report + GUI Tab | ✅ выполнен | -| 9 | FTS5 Search: Rebuild Index + GUI Search Bar | ✅ выполнен | -| 10 | Plugins System (Lua + Templates) | ✅ выполнен | -| 11 | Sync Server Skeleton | ⬜ не начат | -| 12 | Sync Client MVP | ⬜ не начат | -| 13 | Activity + File Scanner/Watcher | ⬜ не начат | -| 14 | TUI MVP (Bubble Tea) | ⬜ не начат | -| 15 | Integrity Check + Repair + Vault Restore | ⬜ не начат | -| 16 | Plugins System (Lua + Templates) | ⬜ не начат | +| 6 | GUI (browser prototype): Sidebar + Main Panel | ✅ выполнен | +| 7 | Actions + Worklog | ✅ выполнен | +| 8 | FTS5 Search | ✅ выполнен | +| 9 | Section assignment + Sidebar filtering | ✅ выполнен | +| 10 | Plugin Manager (discovery + templates) | ✅ выполнен | +| 11 | **Wails Desktop GUI** | ⬜ не начат | +| 12 | **Files/Folders full workflow** | ⬜ не начат | +| 13 | **Drag-and-drop** | ⬜ не начат | +| 14 | **MVP stabilization** | ⬜ не начат | +| 15 | Sync Server Skeleton | 🔒 приостановлен | +| 16 | Sync Client MVP | 🔒 приостановлен | +| 17 | Activity + File Scanner/Watcher | 🔒 приостановлен | +| 18 | TUI MVP (Bubble Tea) | 🔒 приостановлен | +| 19 | Integrity Check + Repair | 🔒 приостановлен | +| 20 | Plugins: Lua runtime | 🔒 приостановлен | +| 21 | DokuWiki Importer (plugin) | 🔒 приостановлен | + +> 🔒 = **PAUSED** — не начинать до завершения шага 14 (MVP stabilization). --- -## ШАГ 1 — Git Init + Skeleton +## Выполненные шаги (1-10) -**Цель:** репозиторий создан, пустая структура, "hello world" билдится. - -**Acceptance:** -- `go build ./...` проходит -- `go test ./...` проходит -- `verstak --version` выводит версию -- Повторный init безопасен - -**Действия:** -- git init, .gitignore (Go, Wails) -- `go mod init verstak` -- Структура: `cmd/verstak/`, `internal/core/`, `migrations/` -- `cmd/verstak/main.go`: --version flag +### ШАГ 1 — Git Init + Skeleton +- go module `verstak`, структура cmd/internal/migrations +- CLI `verstak --version` - README.md -**Commit:** `step 1: skeleton` +### ШАГ 2 — Init + SQLite +- storage.go: DB wrapper, migration runner +- vault.go: Init() создаёт .verstak/ + index.db +- config.go: YAML config + +### ШАГ 3 — Nodes Repository +- Node struct + CRUD (Create, Get, ListChildren, ListRoots, UpdateTitle, Move, SoftDelete) +- Meta KV + tests + +### ШАГ 4 — Files +- FileService: AddExternal, CopyIntoVault, Get, ListByNode, MarkMissing, DeleteToTrash, Open +- file_test.go: 5 tests + +### ШАГ 5 — Notes +- NoteService: Create, Read, Save (с backup), Delete +- note_test.go: 3 tests + +### ШАГ 6 — GUI (browser prototype) +- Go HTTP SPA на случайном порту +- Sidebar tree + разделы (Сегодня, Неразобранное, Клиенты, Проекты...) +- Dashboard дела + вкладки (Обзор, Заметки, Файлы, Действия, Журнал, Активность) +- Модальное окно "+ Добавить" с выбором типа +- Поиск по корневым нодам +- **Это legacy prototype — не развивать как основной GUI** + +### ШАГ 7 — Actions + Worklog +- ActionService: Create, Get, ListByNode, Delete, Run (open_url/file/folder, run_command) +- WorklogService: Add, Update, ListByNode, Delete, SumMinutes, Report +- CLI: `action add/list/run/delete`, `log add/list/report` +- GUI вкладки с кнопками действий и журналом работ + +### ШАГ 8 — FTS5 Search +- SearchService: Index, Remove, Rebuild, Search (FTS5 MATCH) +- FTS5 virtual table создаётся лениво (работает с/без FTS5) +- Fallback на LIKE по заголовкам нод +- CLI: `verstak index rebuild` +- GUI search bar + +### ШАГ 9 — Section assignment +- Колонка `section` в nodes (clients/projects/recipes/documents/archive/inbox) +- Фильтрация разделов по `?section=` в API +- Root-ноды без section → inbox + +### ШАГ 10 — Plugin Manager +- Discovery: `.verstak/plugins//plugin.json` +- Enable/disable, templates → pre-filled node trees +- Built-in шаблон "Клиент" (Overview + Документы/Переписка/Скриншоты) +- Template selector в модалке создания дела +- POST /api/nodes/from-template +- CLI: `plugin list/enable/disable/templates` +- Lua runtime — stub (placeholder) --- -## ШАГ 2 — Init + SQLite + First Migration +## Текущий этап: ШАГ 11 — Wails Desktop GUI -**Цель:** `verstak init --vault ./test` создаёт vault с index.db. +**Целевой commit:** `gui/wails-file-workflow` -**Acceptance:** -- `go test ./...` проходит -- init создаёт `.verstak/index.db` -- повторный init безопасен +Архитектура: -**Действия:** -- migration runner (cmd + SQL migrations/) -- миграция 001_init.sql (таблица nodes) -- `_ "github.com/mattn/go-sqlite3"` или modernc driver -- CLI `init`: vault dir + `.verstak/` + `index.db` +``` +┌─────────────────────────────────────────────────┐ +│ Frontend (Wails) │ +│ frontend/src/ │ +│ App.svelte │ +│ components/Sidebar, TopBar, CaseView, ... │ +│ stores/selection, nodes, files, ui │ +│ styles/theme.css │ +└──────────────────┬──────────────────────────────┘ + │ Wails bindings +┌──────────────────▼──────────────────────────────┐ +│ Go Core (internal/core/) │ +│ nodes, vault, storage, notes, files, │ +│ actions, worklog, search, plugins │ +└──────────────────┬──────────────────────────────┘ + │ +┌──────────────────▼──────────────────────────────┐ +│ Vault filesystem + SQLite │ +└─────────────────────────────────────────────────┘ +``` -**Commit:** `step 2: init + sqlite + first migration` +### Действия + +1. Создать Wails app skeleton (`wails init`) +2. Структура frontend/ — Svelte/Vue/vanilla TS +3. Backend bindings — методы Wails над core services +4. Перенести текущий UI shell из inline HTML в frontend +5. Оставить текущий `internal/gui/` как legacy (не удалять, но не развивать) + +### Backend bindings (минимум) + +```go +// Nodes +ListSections() ([]SectionDTO, error) +ListNodes(section string) ([]NodeDTO, error) +GetNodeDetail(nodeID string) (NodeDetailDTO, error) +CreateNode(parentID, section, typ, title string) (NodeDTO, error) +FromTemplate(parentID, section, typ, title, template string) (NodeDTO, error) +DeleteNode(id string) error +MoveNode(id, parentID string) error + +// Notes +CreateNote(parentID, title string) (NodeDTO, error) +ReadNote(noteID string) (string, error) +SaveNote(noteID, content string) error + +// Files +ListFiles(nodeID string) ([]FileDTO, error) +AddPathCopy(nodeID, sourcePath string) ([]NodeDTO, error) // файл или папка +AddPathLink(nodeID, sourcePath string) ([]NodeDTO, error) +DeleteFileOrFolder(id string) error +OpenFile(id string) error +OpenFolder(id string) error +PickFile() (string, error) +PickDirectory() (string, error) + +// Actions/Worklog/Search +ListActions(nodeID string) ([]ActionDTO, error) +RunAction(id string) error +CreateWorklog(nodeID, summary string, minutes int) (WorklogDTO, error) +Search(query string) ([]SearchResultDTO, error) +``` --- -## ШАГ 3 — Nodes Repository + CRUD + CLI Node +## ШАГ 12 — Files/Folders full workflow -**Цель:** можно создать/прочитать/переместить/удалить дело через CLI. +### Core service extensions -**Acceptance:** -- nodes + node_meta таблицы -- NodeRepository: Create, Get, ListChildren, UpdateTitle, Move, SoftDelete -- CLI: `node create`, `node list`, `node move`, `node delete` -- unit tests проходят +Расширить `files.Service`: -**Действия:** -- Полная схема nodes (id, parent_id, type, title, slug, path, sort_order, created_at, updated_at, deleted_at, revision, device_id) -- node_meta (node_id, key, value) -- Node struct + Repository -- UUID вместо auto-increment -- Soft delete (deleted_at) -- безопасный slug для path -- Tests: in-memory SQLite +```go +AddPathCopy(nodeID string, sourcePath string) ([]Node, error) +AddPathLink(nodeID string, sourcePath string) ([]Node, error) +``` -**Commit:** `step 3: nodes repository + CRUD` +Логика: +- `os.Stat(sourcePath)` → если директория → рекурсивный обход +- Каждый файл → File node + file record +- Каждая папка → Folder node +- Структура сохраняется через parent_id + +### Folder model + +Папка = node type `folder` (не file record с mime=directory). + +При импорте `romashka-docs/`: +``` +Folder node: romashka-docs (type=folder) + File node: dogovor.docx (type=file) + Folder node: screenshots (type=folder) + File node: error.png (type=file) +``` + +### Name conflict resolution + +Если в target уже есть `docs`: +``` +docs +docs (2) +docs (3) +``` + +### Safety checks + +При добавлении папки показать summary: +- количество файлов/папок +- общий размер +- предупреждение если > 1000 файлов, > 1 GB, содержит `.git`/`node_modules`/`.cache` + +### Trash + +- Soft delete node + children +- Vault files → `.verstak/trash` +- External files — только удалить связь +- Не `rm -rf` + +### Tests + +1. Copy single file → vault, record created, source intact +2. Link single file → no copy, external path saved +3. Copy folder → tree created, files in vault +4. Link folder → node created, no content copied +5. Delete vault file → soft-deleted, file in trash +6. Delete vault folder → children soft-deleted +7. Name conflict → no overwrite, safe suffix +8. Open file → mocked opener (no real app launch) --- -## ШАГ 4 — Vault Files: Trash + File Service + CLI File +## ШАГ 13 — Drag-and-drop -**Цель:** можно добавить файл в дело, открыть системным приложением, удалить в trash. +### External D&D -**Acceptance:** -- `.verstak/trash/` создаётся при init -- copy file into vault работает -- open with system app работает -- delete-to-trash работает -- тесты проходят +Drop target: активное дело / вкладка Файлы / Неразобранное. -**Действия:** -- Таблица files (id, node_id, filename, path, storage_mode, size, sha256, mime, ...) -- VaultService: CopyFile, LinkExternal, OpenFile, DeleteToTrash, RestoreFromTrash -- CLI: `file add`, `file list`, `file open`, `file trash` - -**Commit:** `step 4: vault files + trash + CLI` +После drop → диалог: +``` +Добавить в "ООО Ромашка / Сайт" +Файлов: 3, Папок: 1, 240 MB +[Скопировать] [Переместить] [Привязать] [Отмена] +``` --- -## ШАГ 5 — Markdown Notes: Create/Read/Save + CLI Note +## ШАГ 14 — MVP stabilization -**Цель:** можно создать заметку, писать в неё, читать обратно. - -**Acceptance:** -- type "note" для nodes -- создать .md файл в vault -- save делает backup старой версии -- тесты проходят - -**Действия:** -- Таблица notes (node_id, file_id, format, original_format, encrypted) -- NoteService: CreateNote, ReadNote, SaveNote (с backup) -- CLI: `note create`, `note read`, `note write` -- Backup старой версии перед перезаписью - -**Commit:** `step 5: markdown notes` - ---- - -## ШАГ 6 — Wails GUI MVP - -**Цель:** GUI запускается, видно дерево дел, можно создать дело и заметку. - -**Acceptance:** -- sidebar tree показывает дела -- create node работает -- markdown textarea editor с save -- file list + add file + open file -- главный пользовательский поток работает - -**Действия:** -- Wails app init (Go backend + Svelte/Vue) -- Backend bindings: NodeService, VaultService, NoteService -- Frontend: sidebar tree, main panel, modals, markdown editor -- Поток: дело → заметка → файл → открыть файл - -**Commit:** `step 6: Wails GUI MVP` - ---- - -## ШАГ 7 — Actions - -**Цель:** можно создать кнопку "Открыть сайт", нажать, сайт открылся. - -**Acceptance:** -- open_url, open_file, open_folder, run_command -- confirm_required диалог -- action log -- GUI вкладка "Действия" - -**Действия:** -- Таблица actions -- ActionService: Run с confirm, exec.Command БЕЗ shell, args массивом -- CLI: `action add`, `action list`, `action run` -- GUI: вкладка с кнопками - -**Commit:** `step 7: actions` - ---- - -## ШАГ 8 — Worklog - -**Цель:** можно записать "3ч обновил витрину", скопировать отчёт. - -**Acceptance:** -- add/edit/delete entry -- approximate minutes + billable flag -- copy report копирует в буфер -- GUI вкладка "Журнал" - -**Действия:** -- Таблица worklog_entries -- WorklogService: Add, Edit, Delete, CopyReport -- CLI: `worklog add`, `worklog list`, `worklog report` -- GUI: вкладка журнал + кнопка copy report - -**Commit:** `step 8: worklog` - ---- - -## ШАГ 9 — FTS5 Search - -**Цель:** можно найти "витрину" по заметкам, файлам, журналу. - -**Acceptance:** -- `verstak index rebuild` перестраивает индекс -- поиск по node titles, note content, filenames, worklog summaries -- GUI search bar + результаты с type/path - -**Действия:** -- Таблица search_index (FTS5): node_id, title, content, path, tags, type -- Триггеры для автоматического обновления или manual rebuild -- SearchService: RebuildIndex, Search(query) -- CLI: `index rebuild` -- GUI: search bar в header - -**Commit:** `step 9: FTS5 search` - ---- - -## ШАГ 10 — Система плагинов (Lua + шаблоны дел) - -**Цель:** можно положить Lua-скрипт в `.verstak/plugins/` — и он работает. -Без перекомпиляции программы. - -**Acceptance:** -- `.verstak/plugins//plugin.json` — мета -- `main.lua` — загрузка через gopher-lua -- `on_init`, `on_vault_open`, `on_node_create` хуки -- `verstak.node.register_type()` — новые типы дел -- `verstak.http.route()` — API для GUI -- шаблоны дела (JSON) → предзаполненное дерево -- песочница: нет io/os.execute, только API -- CLI: `verstak plugin list / install / enable` -- DokuWiki импортер — пример плагина в `contrib/plugins/importer-dokuwiki/` - -**Действия:** -- `internal/core/plugins/manager.go` — сканирование, загрузка, валидация -- Lua runtime (gopher-lua) с песочницей -- Plugin API: node, config, activity, http, ui, vault -- Миграции плагинов (SQL) -- Реестр типов дел → GUI рендерит разные карточки -- CLI: plugin list/install/enable -- Базовый шаблон дела (client.json) -- Пример плагина: DokuWiki importerв `contrib/` - -**Commit:** `step 10: plugins system` - ---- - -## ШАГ 11 — Sync Server Skeleton - -**Цель:** verstak-server отвечает на /health, /sync/push, /sync/pull, /blobs. - -**Acceptance:** -- HTTP server на отдельном порту -- API key auth -- blob storage by sha256 -- GET /health, POST /sync/push, POST /sync/pull, POST /blobs/upload, GET /blobs/{sha256} - -**Действия:** -- `cmd/verstak-server/main.go` -- SQLite server db -- Push/pull operations endpoints -- Blob upload/download with sha256 naming - -**Commit:** `step 11: sync server skeleton` - ---- - -## ШАГ 12 — Sync Client MVP - -**Цель:** `verstak sync` отправляет локальные операции на сервер и получает обратно. - -**Acceptance:** -- sync_ops таблица -- операции создаются при каждом изменении -- push local ops + pull remote ops -- upload/download blobs -- conflict copy при неуверенности - -**Действия:** -- Таблица sync_ops (опционально добавить триггеры в repository) -- SyncClient: Push, Pull, UploadBlob, DownloadBlob -- CLI: `verstak sync` -- Server URL + API key в .verstak/config - -**Commit:** `step 12: sync client MVP` - ---- - -## ШАГ 13 — Activity + File Scanner/Watcher - -**Цель:** фиксируется открытие/редактирование, scanner видит новые файлы. - -**Acceptance:** -- activity_events таблица -- scanner сравнивает реальность с SQLite -- watcher (fsnotify) ускоряет обнаружение -- экран "Активность" с группировкой по делу -- можно создать worklog из events - -**Действия:** -- Таблица activity_events -- Запись событий из nodes/notes/files/actions -- Snapshot scanner (источник правды) -- fsnotify watcher (ускоритель) -- CLI: `scan`, `activity list` -- GUI: экран "Активность" - -**Commit:** `step 13: activity + scanner/watcher` - ---- - -## ШАГ 14 — TUI MVP (Bubble Tea) - -**Цель:** быстрый поиск дела, добавление worklog, запуск action. - -**Acceptance:** -- fuzzy search tree -- open node -- add worklog -- run action -- sync now - -**Действия:** -- `cmd/verstak-tui/main.go` с Bubble Tea -- Модели: search, node view, worklog form, action runner -- Не повторяет весь GUI — только быстрые действия - -**Commit:** `step 14: TUI MVP` - ---- - -## ШАГ 15 — Integrity Check + Repair + Vault Restore - -**Цель:** `verstak vault check` находит проблемы, repair чинит, restore восстанавливает. - -**Acceptance:** -- check: missing files, orphan files, SQLite references, hash mismatch -- repair: устраняет найденные проблемы -- restore с сервера восстанавливает vault - -**Действия:** -- CLI: `vault check` — сканирует и отчитывается -- CLI: `vault repair` — чинит найденное -- CLI: `restore --server --api-key --target ` - -**Commit:** `step 15: integrity + restore` - ---- - -## ШАГ 16 — Система плагинов (Lua + шаблоны дел) - -**Цель:** можно положить Lua-скрипт в `.verstak/plugins/` — и он работает. - -**Acceptance:** -- `.verstak/plugins//plugin.json` — мета -- `main.lua` — загрузка через gopher-lua -- `on_init`, `on_vault_open`, `on_node_create` хуки -- `verstak.node.register_type()` — новые типы дел -- `verstak.http.route()` — API для GUI -- шаблоны дела (JSON) → предзаполненное дерево -- CLI: `verstak plugin list / install / enable` - -**Действия:** -- `internal/core/plugins/manager.go` — сканирование, загрузка, валидация -- Lua runtime (gopher-lua) с песочницей -- Plugin API: node, config, activity, http, ui, vault -- Миграции плагинов (SQL) -- Реестр типов дел → GUI рендерит разные карточки -- CLI: plugin list/install/enable -- Базовый шаблон дела (client.json) - -**Commit:** `step 10: plugins system` +- Smoke tests базовых сценариев +- Проверка: дело → заметка → файл → папка → trash → перезапуск +- go test ./... pass +- Обновление документации +- Остановка перед следующими фичами --- @@ -382,10 +269,19 @@ verstak/ cmd/ verstak/ # CLI - verstak-gui/ # Wails GUI + verstak-gui/ # Wails GUI main verstak-tui/ # Bubble Tea TUI verstak-server/ # Sync server + frontend/ # Wails frontend + package.json + wails.json + src/ + App.svelte + components/ + stores/ + styles/ + internal/ core/ nodes/ @@ -400,9 +296,11 @@ verstak/ sync/ security/ config/ - plugins/ + plugins/ # manager, lua (stub) - frontend/ # Wails frontend (Svelte/Vue) + contrib/ + plugins/ + importer-dokuwiki/ migrations/ 001_init.sql @@ -411,15 +309,11 @@ verstak/ 004_add_notes.sql 005_add_actions.sql 006_add_worklog.sql - 007_add_activity.sql - 008_add_fts.sql - 009_add_sync.sql ``` -## RAID (Risks, Assumptions, Issues, Dependencies) +## RAID -- **Критично:** Wails v3 может быть нестабилен — проверить перед шагом 6 -- **Критично:** go-sqlite3 нужен cgo; modernc — чистый Go, выбрать до шага 2 -- **Зависимость:** Шаги 12 (sync client) зависят от 11 (server) -- **Зависимость:** Шаг 6 (GUI) лучше откладывать до стабильности core -- **Риск:** Svelte/Vue фронтенд потребует node/npm — подготовить +- **Критично:** Wails требует Node.js для frontend-сборки +- **Критично:** go-sqlite3 + cgo; gcc уже установлен +- **Зависимость:** Steps 15+ ждут завершения step 14 +- **Риск:** Wails v3 может быть нестабилен — проверить перед шагом 11