mirivlad
2487d3bbaa
Files tab: multi-selection, drag-and-drop, keyboard shortcuts, custom confirm modal, SVG icons
2026-06-01 01:16:51 +08:00
mirivlad
645d8878cc
gui: complete Wails v2 vertical MVP — fixes, search, polished UI
...
Backend fixes:
- Wire search service in App struct, implement Search() bindings
- Fix OpenFile to use files.Service.Open() instead of stub
- Fix OpenFolder to open spaces/<slug>/ instead of vault root
- Remove unused imports and dead code in app.go
Frontend fixes:
- Add missing Svelte plugin to vite.config.js (blocking build error)
- Fix optional catch binding for compatibility
- Fix select dropdown rendering on Linux (appearance: none + custom arrow)
- Switch api/verstak.js to use generated Wails v2 bindings
- Include hand-written wailsjs bindings in repository
- Add build.sh to repository
Build:
cd frontend && npm run build
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
2026-05-31 23:48:38 +08:00
mirivlad
b4010a5a24
gui: Wails v2 vertical MVP — bindings + UI
...
Go bindings (cmd/verstak-gui/app.go):
- Wire notes.Service, files.Service, actions.Service, worklog.Service
- CreateNote, ListNotes, ReadNote, SaveNote
- ListFiles, ListActions, RunAction
- ListWorklog, CreateWorklog
- Fix DTO mappings for core types
Frontend (frontend/src/):
- api/verstak.js: Wails v2 API wrapper (window.go.main.App)
- App.svelte: full rewrite with sidebar + 6 tabs + notes editor
- Section filtering → nodes by section
- Notes: create, open textarea editor, save, dirty tracking
- Quick actions, worklog entries, empty states
- Node creation modal with section select
Build:
cd frontend && npm run build
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
2026-05-31 20:37:46 +08:00
mirivlad
4a8f4e3319
docs: mark Wails vertical MVP as current stage
2026-05-31 20:15:45 +08:00
mirivlad
ee503c338f
gui: fix layout — full viewport, dark theme, sidebar+main
...
Problem: UI appeared as narrow dark panel on white background with scrollbar.
Root causes:
- html/body had no reset — default browser margin/padding = white borders
- index.html referenced non-existent /style.css
- .app used height:100vh but no width:100vw or overflow:hidden
- sidebar used fixed width instead of flexbox
Fixed:
- index.html: added critical CSS reset (html/body/#app = 100%, margin:0, overflow:hidden, dark bg)
- index.html: removed /style.css ref, changed lang to ru, title to Верстак
- App.svelte: complete layout rewrite
- .app = flex, 100vw x 100vh, overflow:hidden
- sidebar = 260px width, full height, flex column
- main = flex:1, full height, flex column (header + content)
- sidebar nav with sections + nodes using <button> elements
- content area fills remaining space
- proper dark theme colors throughout
- Rebuilt frontend/dist and cmd/verstak-gui/frontend-dist
2026-05-31 19:54:07 +08:00
mirivlad
3e07e611dd
docs: update PLAN.md with Wails v2 build instructions
2026-05-31 19:42:43 +08:00
mirivlad
77a7918569
gui: port frontend to Wails v2
...
Frontend build failure root cause:
- Vite 8 uses rolldown with Wails v3 typed-events plugin
- @wailsio/runtime (Wails v3) in frontend dependencies
- vite.config.js had wails('./bindings') plugin from Wails v3 template
- main.js used Svelte 5 mount() API but Svelte 4 required
Fixes:
- Remove @wailsio/runtime dependency
- Remove wails('./bindings') plugin from vite.config.js
- Replace Vite 8 with Vite 5.4.21 + Rollup (stable)
- Downgrade Svelte 5 to Svelte 4.2.19
- Downgrade @sveltejs/vite-plugin-svelte to v3.1.2
- Fix main.js: mount() -> new App({ target })
- Rewrite App.svelte with Wails v2 binding calls (window.go.main.App.*)
- UI: sidebar with sections, nodes, basic navigation
Build: cd frontend && npm run build -> dist/ (476ms)
Build GUI: go build -tags 'gui production webkit2_41' -o verstak-gui ./cmd/verstak-gui
Run: ./verstak-gui (window opens, no SIGSEGV)
2026-05-31 19:39:49 +08:00
mirivlad
c65187f656
gui: add Wails v2 app skeleton
...
- Install Wails v2.12.0 CLI (go install github.com/wailsapp/wails/v2/cmd/wails@latest)
- Add go.mod require: github.com/wailsapp/wails/v2 v2.12.0
- Create cmd/verstak-gui/main.go: Wails v2 entry point (go:build gui)
- Uses wails.Run() with AssetServer + Bind
- embed frontend-dist (copy of frontend/dist for build)
- Init core services: nodes, files, notes, actions, worklog, search, plugins
- Create cmd/verstak-gui/app.go: App struct with Wails v2 bindings
- ListSections, ListRootNodes, ListChildren, ListNodesBySection
- GetNodeDetail, CreateNode, DeleteNode
- PickFile, PickFiles, PickDirectory (runtime dialogs)
- Stubs for: Notes, Files, Actions, Worklog, Search
- Legacy HTTP GUI preserved in internal/gui/
- Build: go build -tags "gui production webkit2_41" -o verstak-gui ./cmd/verstak-gui
- Wails v2 window opens on Linux desktop (no SIGSEGV!)
- Core tests pass: go test ./...
2026-05-31 19:11:20 +08:00
mirivlad
2e50e95b68
docs: update PLAN.md — Wails v3→v2 migration note, PAUSED status
2026-05-31 18:46:24 +08:00
mirivlad
ae970e5bca
gui: remove Wails v3 dependencies and v3-specific files
...
- Remove guimain.go (Wails v3 entry point with //go:build gui)
- Remove wails_service.go (Wails v3 binding stubs)
- Remove go.mod requires for wails/v3, webview2, and all v3 indirect deps
- Remove vendor/ directory (leftover from Wails v3 init)
- Clean go.mod to only core dependencies: sqlite3, uuid, yaml.v3
- Core tests still pass: go test ./...
2026-05-31 18:44:04 +08:00
mirivlad
600b67bc1e
gui: add Wails v3 desktop app skeleton
...
- Go upgraded to 1.25.10 (required by Wails v3)
- Wails v3 installed (alpha.96)
- Frontend: Svelte+Vite scaffold in frontend/
- guimain.go: Wails GUI entry point (compiled with -tags gui)
- wails_service.go: stub service for Wails bindings
- Verstak desktop binary builds: go build -tags gui -o verstak-gui .
- CLI (./cmd/verstak/) unaffected
- Legacy HTTP GUI (internal/gui/) preserved as prototype
- Build: 24MB ELF binary with GTK4/WebKit2GTK-6
Build commands:
CLI: go build -o verstak ./cmd/verstak/
GUI: cd frontend && npm run build && go build -tags gui -o verstak-gui .
2026-05-31 15:45:52 +08:00
mirivlad
537e8a126e
plan: rewrite for Wails GUI + full file/folder workflow
...
- 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
2026-05-31 12:10:58 +08:00
mirivlad
752b1bb4b8
fix: file upload via GUI + API endpoint
...
- Replace stub file modal with working file path input
- PUT /api/files/upload — copies external file into vault
- submitFile() JS: posts path to API, refreshes node view
- Button '+ Файл' now opens functional modal
2026-05-31 11:38:49 +08:00
mirivlad
b800bce7e4
step 10: plugins system (Lua + templates) + DokuWiki as optional plugin
...
Plugin Manager:
- Discover plugins from .verstak/plugins/<name>/plugin.json
- Enable/disable per plugin
- Template definitions (JSON) → pre-filled node trees
- SQL migrations from plugins
- Built-in templates loaded from internal/core/plugins/builtin/templates/
Lua Runtime:
- Stub (gopher-lua placeholder) — ready for real implementation
- When dep added: hooks (on_init, on_vault_open, on_node_create),
sandbox (no io/os.execute), Plugin API
GUI:
- Template selector in create node modal
- POST /api/nodes/from-template creates tree from template
- Built-in "Клиент" template: Overview note + Документы/Переписка/Скриншоты
CLI:
- verstak plugin list/enable/disable/templates
DokuWiki Importer:
- Moved to contrib/plugins/importer-dokuwiki/ (optional plugin)
- plugin.json + migration + README
DokuWiki removed from MVP core — now an opt-in plugin.
Acceptance: go build ./... pass, go test ./... pass (all packages).
2026-05-31 11:20:45 +08:00
mirivlad
d6f7f1a9b8
steps 8+9: worklog + FTS5 search
...
STEP 8 — Worklog:
- Migration 006: worklog_entries table (node_id, date, minutes,
approximate, billable, summary, details)
- WorklogService: Add, Get, Update, Delete, ListByNode, SumMinutes,
Report (text report generator with total time)
- CLI: verstak log add/list/report (verstak log --help for usage)
- GUI tab: entries list with date/time/approx, add form with
minutes+text+approx checkbox, total minutes counter
STEP 9 — FTS5 Search:
- FTS5 virtual table created lazily by search.Rebuild()
(works with/without FTS5 compiled in — graceful fallback)
- SearchService: Index, Remove, Rebuild, Search (with FTS5 MATCH)
- CLI: verstak index rebuild — builds search index from node titles
- GUI search bar uses /api/search?q= (FTS5 when available,
fallback to LIKE on node titles)
Acceptance: go build ./... pass, go test ./... pass (all packages).
2026-05-31 02:25:25 +08:00
mirivlad
dae53fcbba
step 7: actions — table, service, CLI, GUI tab + confirm dialog
...
- Migration 005: actions table (node_id, title, kind, command, args_json,
working_dir, url, confirm_required, capture_output)
- ActionService: Create, Get, ListByNode, Delete, Run
Run dispatches: open_url/file/folder (xdg-open), run_command/script
(exec.Command), open_terminal, launch_app
- CLI: verstak action add/list/run/delete
'run' shows confirm prompt for confirm_required actions
- GUI 'Действия' tab: button list with kind label, confirm_required
opens editor overlay with action info + confirm, delete button
- 7 unit tests for ActionService
Acceptance: go build ./... pass, go test ./... pass.
2026-05-31 01:52:23 +08:00
mirivlad
9ee6df0d3f
feat: node section assignment for sidebar filtering + search fix
...
Backend:
- Migration 004: add 'section' column to nodes table
(NULL=inbox, values: clients/projects/recipes/documents/archive)
- Create(parentID, type, title, section) — section stored on root nodes
- ListRoots(includeDeleted, section) — filters by section
(section='inbox' returns nodes with NULL section)
- GET /api/nodes?section=X filters root nodes by section
- POST /api/nodes accepts 'section' field in body
Frontend:
- Sidebar separates 'НАВИГАЦИЯ' (virtual sections) from 'ДЕЛА' (real nodes)
- Each section loads only its own nodes: GET /api/nodes?section=clients etc.
- Creating from a section sets the section automatically
- Inbox shows only nodes with no section
- selectBySearch(id) closes result dropdown after selection
- All types shown in Russian (Дело, Заметка, Папка, etc.)
Acceptance: go build pass, go test pass (all packages),
manual: Pro projects section shows only project-nodes,
clients only client-nodes, inbox only unsectioned nodes.
2026-05-31 01:26:46 +08:00
mirivlad
14ff1a25b9
fix: bind sidebar selection to filtered content
...
Root cause: single global 'cur' node ID was shared across all
sections. Switching between 'Клиенты'/'Проекты'/etc did not
change the rendered content because renderToday/renderInbox/
loadSection all loaded the same flat root-node list and
switchTab('ov') re-rendered selN(cur) regardless of which
section was active.
Fix: split selection into two distinct states:
sel = {kind:'section', section:'today'|'inbox'|'clients'|...}
or sel = {kind:'node', nodeId:'<uuid>'}
Each section renders its own content (title, quick-actions,
filtered items, empty state). Real nodes show their own
dashboard. Tab dispatch checks sel.kind first.
Sidebar separated into:
'НАВИГАЦИЯ' — virtual sections (today/inbox/7 categories)
'ДЕЛА' — real user nodes from API
Russian type labels everywhere (TL map). Section metadata
(SEC_META) provides per-section empty states and action types.
Known limitation: section content currently shows all root
nodes (backend has no section/group column yet). When section
assignment is added to the data model, filtering will wire
up without frontend changes — renderSectionList already
receives the section id.
2026-05-30 21:56:07 +08:00
mirivlad
168625671a
step 6 redesign: dashboard, sidebar sections, add menu, editor UX
...
Per 10-point UX spec:
- Contrast boosted (text #e4e4ef instead of #ccc)
- Dashboard view: badges, quick-actions, grouped sub-items/notes/files
- Notes tab filters by type=note, Files tab shows only files
- Tab placeholders: Actions, Worklog, Activity
- Single + Add button with dropdown menu (case/note/file/action/worklog)
- Sidebar navigation: Today, Inbox, Clients, Projects, Recipes, Docs, Archive
- Russian type labels (no raw CASE/note)
- Note editor: breadcrumb, title, readable-width textarea (720px)
- Wails-ready SPA: inline JS, fetch to /api/*, no external deps
2026-05-30 21:04:18 +08:00
mirivlad
39271fc28f
steps 4-6 + doc overhaul: files, notes, GUI, plugins docs
...
DOCUMENTATION (shift from personal to universal product):
- README.md: rewritten with 'one product, different doors' framing,
universal entities table, audience segments
- 01_Product_Spec.md: removed personal references (sshkeeper, Godot,
DokuWiki, servers), added audience segments (freelancer, repairmaster,
developer, maker, consultant), universal scenarios
- 02_Architecture.md: added 'Plugins (Extensibility)' section with
calendar/kanban/importer/template examples
- 03_Data_Model_Storage.md: added section 6 on plugin extensibility
(node_meta, type registry, SQL migrations per plugin)
- 09_Extensibility.md (NEW): full plugin architecture — Lua runtime,
plugin.json, hooks, sandbox, templates, registry
- PLAN.md: added step 16 (plugins), updated status table
- 00_README.md: rewritten product index with plugin principle
CODE — STEP 4 (Files):
- migration 002: files table (id, node_id, filename, path,
storage_mode, size, sha256, mime, ...)
- FileService: AddExternal, CopyIntoVault, Get, ListByNode,
MarkMissing, DeleteToTrash, Open (xdg-open)
- file_test.go: 5 tests (external, copy-vault, list-node,
delete-trash, MIME guess)
CODE — STEP 5 (Notes):
- migration 003: notes table (node_id PK, file_id, format,
original_format, encrypted)
- NoteService: Create (node+file+link), Read, Save (with backup to
.verstak/history/), Delete, Load
- note_test.go: 3 tests (create-read, save-backup, delete)
CODE — STEP 6 (GUI):
- cmd/verstak-gui/main.go: launches GUI server, opens browser
- internal/gui/server.go: HTTP API for nodes/notes/files/search
- internal/gui/index.html.go: full inline SPA frontend (dark theme,
sidebar tree, cards grid, note editor, search, create modals)
- Navigation: sidebar tree → click node → detail view with
children + files cards → tab switch (overview/notes/files)
→ create node/note via modal → edit note in fullscreen
textarea → save (with history backup)
Acceptance: go build ./... pass, go build -tags gui ./cmd/verstak-gui pass,
go test ./... pass (20+ tests). GUI serves on random port, opens browser.
API returns JSON for all resource types.
2026-05-30 20:35:04 +08:00
mirivlad
69eb909d48
step 3: nodes repository + CRUD + CLI node commands
...
- types.go: TypeSpace/Case/Folder/Note/... + Slugify()
- node.go: Node struct, Meta, IsDeleted/IsRoot helpers
- repository.go: full CRUD (Create, Get, GetActive, ListChildren,
ListRoots, UpdateTitle, Move, SoftDelete) + Meta KV (MetaSet,
MetaGet, MetaList)
- node_cmd.go: thin wrappers around repository
- main.go: verstak node create/list/get/move/delete subcommands
- repository_test.go: 12 tests covering all CRUD paths
Acceptance: go build pass, go test pass (12 tests),
CLI create+list+get+move+delete all working.
2026-05-30 19:09:25 +08:00
mirivlad
b8d8427c46
step 2: init command + SQLite storage + migrations + config
...
- storage.go: DB wrapper, migration runner (in-code SQL strings)
- migrations.go: 001_init (nodes + node_meta + indexes)
- vault.go: Init() creates .verstak/ dirs, config.yml, index.db
- config.go: YAML config read/write
- util/uuid.go: UUIDv7 generator
- cmd/verstak/main.go: init --vault PATH command
- main_test.go: TestInitCreatesVault, TestInitConfigYAML
Acceptance: go build ./... pass, go test ./... pass
Init creates test-vault with .verstak/index.db + config.yml
Repeat Init is safe.
2026-05-30 18:58:47 +08:00
mirivlad
982f3064ac
step 1: skeleton - go module, CLI stub with --version, structure
2026-05-30 18:42:19 +08:00