16 KiB
Верстак — Пошаговый план разработки
Принципы работы
- После каждого шага — СТОП. Влад проверяет, даёт обратную связь.
- Следующий шаг начинается ТОЛЬКО после одобрения.
- Каждый шаг — отдельный git commit.
- Периодически сверяться с этим планом и документацией в docs/.
Статус шагов
| # | Шаг | Статус |
|---|---|---|
| 1 | Git init + Skeleton | ✅ выполнен |
| 2 | Init + SQLite + First Migration | ✅ выполнен |
| 3 | Nodes Repository + CRUD + CLI Node | ✅ выполнен |
| 4 | Vault Files: Trash + File Service + CLI File | ✅ выполнен |
| 5 | Markdown Notes: Create/Read/Save + CLI Note | ✅ выполнен |
| 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 | ✅ выполнено (v2, full Svelte UI) |
| 12 | Files/Folders full workflow | ✅ выполнено (copy/link/import/tree) |
| 13 | Drag-and-drop | ✅ выполнено (internal + external drops) |
| 14 | MVP stabilization | ✅ выполнено — atomicity audit, template children as nodes, fs_path validation, descendant move protection, delete atomicity, sync_apply FS-first rewrite, SafeVaultPath, CreateNodeFromTemplate rollback, 24 integration tests pass. Known gaps: Restore from trash not implemented, applyRemoteNodeUpdate/Move uses FS-first (parent_id + title updates still need full txn), ensureTemplateChildren uses continue on errors |
| 15 | Sync Server + Client | 🔒 PAUSED — HTTP API key, push/pull, blob sync |
| 16 | Activity Suggestions | 🔒 PAUSED — worklog suggestions from activity_events |
| 17 | File Scanner/Watcher | 🔒 PAUSED — fsnotify, snapshot scanner, missing file detection |
| 18 | TUI MVP (Bubble Tea) | 🔒 PAUSED — tree/search, add worklog, run action, sync |
| 19 | Plugins: Lua runtime | 🔒 PAUSED — gopher-lua, hooks, sandbox |
| 20 | Browser Extension | 🔒 PAUSED — tracking, capture, evidence |
| 21 | Calendar/Kanban | 🔒 PAUSED — view by date, board view |
| 22 | Integrity Check + Repair | 🔒 PAUSED — checksums, crash recovery |
| 23 | New templates/integrations | 🔒 PAUSED — community plugins |
🔒 = PAUSED — не начинать до завершения шага 14 (MVP stabilization). Текущий статус: ✅ MVP stabilization завершена — все операции атомарны (DB+FS), template файлы/папки создаются как полноценные ноды с rollback, fs_path валидируется, sync_apply FS-first с SafeVaultPath, delete находит ошибки trash-переноса, 24 integration tests проходят. Известные пробелы: Restore не реализован, ensureTemplateChildren продолжает при ошибках (backward compat), parent_id+title в applyRemoteNodeUpdate без полной транзакции.
Wails v3 → v2 migration: Wails v3 alpha.96 показал SIGSEGV на Linux desktop (GTK/X11). Wails v2 stable выбран как GUI base для MVP. Миграция в процессе (ветка
gui/migrate-wails-v2).
GUI Build (Wails v2):
cd frontend && npm run build && cd ..
rm -rf cmd/verstak-gui/frontend-dist && cp -r frontend/dist cmd/verstak-gui/frontend-dist
go build -tags "gui production webkit2_41" -o verstak-gui ./cmd/verstak-gui
./verstak-gui
Или для dev режима: wails dev (требует Wails v2 CLI)
Текущий этап: MVP Stabilization ✅
Цель: стабилизация MVP — атомарность операций, template ноды, fs_path инварианты, sync roundtrip тесты.
Прогресс Wails v2 Desktop GUI:
- ✅ Wails v2 shell (window opens, no SIGSEGV)
- ✅ Layout fix (full viewport, dark theme, sidebar+main)
- ✅ Notes bindings + UI (create/read/save/dirty state)
- ✅ Tabs (Overview/Notes/Files/Actions/Worklog/Activity)
- ✅ Node creation + template selection (FromTemplate)
- ✅ Section filtering
- ✅ File tree with breadcrumbs, preview, CRUD (rename/delete/duplicate/cut/copy/paste)
- ✅ Drag-and-drop (internal + external OS file drops)
- ✅ Actions CRUD (create/list/run/delete)
- ✅ Worklog entry form
- ✅ Today dashboard + Activity feed (global + per-case)
- ✅ Search
- ✅ Import dialog with safety checks (PreviewImport)
- ✅ Keyboard shortcuts
Среднесрочные шаги (заморожены до стабилизации MVP):
- Sync server/client
- File Scanner/Watcher
- TUI (Bubble Tea)
- Activity suggestions
- Lua runtime
- Browser extension
Выполненные шаги (1-10)
ШАГ 1 — Git Init + Skeleton
- go module
verstak, структура cmd/internal/migrations - CLI
verstak --version - README.md
ШАГ 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/<name>/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)
Текущий этап: ШАГ 11 — Wails Desktop GUI
Целевой commit: gui/wails-file-workflow
Архитектура:
┌─────────────────────────────────────────────────┐
│ 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 │
└─────────────────────────────────────────────────┘
Действия
- Создать Wails app skeleton (
wails init) - Структура frontend/ — Svelte/Vue/vanilla TS
- Backend bindings — методы Wails над core services
- Перенести текущий UI shell из inline HTML в frontend
- Оставить текущий
internal/gui/как legacy (не удалять, но не развивать)
Backend bindings (Wails v2 — реализовано)
// Nodes
ListSections() []SectionDTO
ListNodesBySection(section string) ([]NodeDTO, error)
GetNodeDetail(nodeID string) (*NodeDTO, error)
ListChildren(parentID string) ([]NodeDTO, error)
CreateNode(parentID, typ, title, section string) (*NodeDTO, error)
DeleteNode(id string) error
MoveNode(nodeID, newParentID string) error
RenameNode(nodeID, newTitle string) error
// Templates
ListTemplates() []TemplateDTO
FromTemplate(parentID, typ, title, section, template string) (*NodeDTO, error)
// Notes
ListNotes(nodeID string) ([]NodeDTO, error)
CreateNote(parentID, title string) (*NodeDTO, error)
ReadNote(noteID string) (string, error)
SaveNote(noteID, content string) error
// Files
ListFiles(nodeID string) ([]FileDTO, error)
ListItems(nodeID string) ([]FileTreeItemDTO, error)
AddPathCopy(nodeID, sourcePath string) ([]NodeDTO, error)
AddPathLink(nodeID, sourcePath string) ([]NodeDTO, error)
DeleteFileOrFolder(nodeID string) error
CreateEmptyFile(parentID, filename string) (*NodeDTO, error)
DuplicateNode(nodeID string) (*NodeDTO, error)
OpenFile(fileID string) error
OpenFolder(nodeID string) error
ReadFileText(fileID string) (string, error)
GetFileBase64(fileID string) (string, error)
PreviewImport(sourcePath string) (*ImportSummary, error)
ValidateName(name string) error
PickFile() (string, error)
PickFiles() ([]string, error)
PickDirectory() (string, error)
// Actions
ListActions(nodeID string) ([]ActionDTO, error)
CreateAction(nodeID, kind, title, data string) (*ActionDTO, error)
DeleteAction(id string) error
RunAction(id string) error
// Worklog
ListWorklog(nodeID string) ([]WorklogDTO, error)
CreateWorklog(nodeID, summary string, minutes int) (*WorklogDTO, error)
// Search
Search(query string) ([]SearchResultDTO, error)
// Activity
ListTodayView() (*TodayDashboardDTO, error)
ListActivityFeed(limit, offset int) ([]EventDTO, error)
ListActivityByNode(nodeID string, limit, offset int) ([]EventDTO, error)
CountActivityByNode(nodeID string) (int, error)
ШАГ 12 — Files/Folders full workflow
Core service extensions
Расширить files.Service:
AddPathCopy(nodeID string, sourcePath string) ([]Node, error)
AddPathLink(nodeID string, sourcePath string) ([]Node, error)
Логика:
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
- Copy single file → vault, record created, source intact
- Link single file → no copy, external path saved
- Copy folder → tree created, files in vault
- Link folder → node created, no content copied
- Delete vault file → soft-deleted, file in trash
- Delete vault folder → children soft-deleted
- Name conflict → no overwrite, safe suffix
- Open file → mocked opener (no real app launch)
ШАГ 13 — Drag-and-drop
External D&D
Drop target: активное дело / вкладка Файлы / Неразобранное.
После drop → диалог:
Добавить в "ООО Ромашка / Сайт"
Файлов: 3, Папок: 1, 240 MB
[Скопировать] [Переместить] [Привязать] [Отмена]
ШАГ 14 — MVP stabilization
- Smoke tests базовых сценариев
- Проверка: дело → заметка → файл → папка → trash → перезапуск
- go test ./... pass
- Обновление документации
- Остановка перед следующими фичами
Структура репозитория
verstak/
go.mod
README.md
PLAN.md
cmd/
verstak/ # CLI
verstak-gui/ # Wails v2 GUI main
frontend/ # Wails v2 Svelte frontend
package.json
vite.config.js
src/
App.svelte
FileTreeRow.svelte
lib/
FileBreadcrumbs.svelte
FilePreviewModal.svelte
ConfirmModal.svelte
FileIcon.svelte
FileActions.svelte
fileUtils.js
api/verstak.js
internal/
core/
nodes/
vault/
storage/
notes/
files/
actions/
worklog/
activity/
search/
config/
plugins/ # manager, lua (stub), builtin templates
contrib/
plugins/
importer-dokuwiki/
migrations/
001_init.sql
002_add_meta.sql
003_add_files.sql
004_add_notes.sql
005_add_actions.sql
006_add_worklog.sql
007_search.sql
008_sync.sql
009_section.sql
RAID
- Критично: Wails требует Node.js для frontend-сборки
- Критично: go-sqlite3 + cgo; gcc уже установлен
- Зависимость: Steps 15+ ждут завершения step 14 (MVP stabilization)
Phase 4: Template-Driven Architecture
Implemented in this commit:
- Template system — built-in system templates for folder, project, client, document, and recipe types.
Each template defines default modules, default files (
Overview.md), and default subfolders. - Vault layout — human-readable folder structure on disk. Every node gets a folder named after its title (sanitized). Nesting reflects parent-child relationships. UUIDs are never exposed in user paths.
.verstak/directory — app-internal data (db, backups, thumbnails, cache, sync, trash, history).- i18n keys — new locale keys for
nav.*,template.*,common.archive, andmigrate.*namespaces added to bothru.jsonanden.json. - Documentation —
docs/VAULT_LAYOUT.md(vault folder structure, rules, migration) anddocs/TEMPLATES.md(system templates, template structure JSON, UI integration).