mirivlad
88eb99e9af
fix: verstak:// links in preview, case-insensitive search, keyboard layout swap
...
1. Fix verstak:// links rendered as blocked/strikethrough in markdown preview:
- Changed href from 'javascript:void(0)' to hash-based '#verstak-type-id'
- DOMPurify no longer strips the link; click handler uses data-verstak-href
- CSS already handles .md-link--internal with cyan color, no strikethrough
2. Add markdown label escaping for internal link picker:
- New escapeMarkdownLabel() in markdown.ts escapes [ ] ( )
- Applied in InternalLinkPicker.selectResult() before inserting markdown
3. Fix case-insensitive search for RU/EN:
- Add title_lower column (migration 019) populated by Go strings.ToLower
- BackfillTitleLower() runs after migrations to populate existing rows
- Search() now queries title_lower with Go-level lowercase (Unicode-aware)
- insertNode() and UpdateTitle() populate title_lower automatically
- New migration 019 + BackfillTitleLower in storage.go
- Tests: TestSearchCaseInsensitive, TestSearchFindsCreatedNode
4. Add keyboard layout swap search support:
- New keyboardLayout.ts utility with RU↔EN QWERTY mapping
- expandKeyboardVariants() generates original + swapped + lowercased variants
- InternalLinkPicker.search() queries all variants in parallel, deduplicates by ID
- Examples: dthcnfr → верстак, руддщ → hello
Files changed:
- markdown.ts: hash href + escapeMarkdownLabel export
- InternalLinkPicker.svelte: label escaping + layout swap search
- keyboardLayout.ts: new RU/EN layout swap utility
- repository.go: title_lower in Search/insertNode/UpdateTitle
- storage.go: migration019 + BackfillTitleLower
- migrations_019.sql.go: new migration
- search_test.go, repository_test.go: new tests
2026-06-15 10:39:44 +08:00
mirivlad
84d9725b17
feat: ШАГ 2 — Staging-таблица browser_events + Store
2026-06-06 18:27:00 +08:00
mirivlad
358c649b42
feat: ШАГ 1 — Bridge HTTP-сервер для браузерного расширения
...
- internal/core/bridge/ — лёгкий HTTP-сервер на 127.0.0.1
- POST /api/events — приём батча событий от расширения
- GET /api/ping — healthcheck для расширения
- X-Verstak-Secret — аутентификация по shared-secret
- AutoGenPort — случайный порт если 9786 занят
- config.BridgeConfig — порт, секрет, auto_gen_port
- App: интеграция startBridge/stopBridge при open/close vault
- bindings_bridge.go — BridgeInfo(), startBridge(), saveBridgeConfig()
- Тесты: ping, auth, success, empty batch, secret gen, auto-port
2026-06-06 18:23:47 +08:00
mirivlad
10b287de7b
feat: aggregate journals across node subtrees
2026-06-05 12:37:25 +08:00
mirivlad
bcb093d453
feat: resolve inbox links separately
2026-06-05 07:33:10 +08:00
mirivlad
fd99dd4f5c
feat: worklog source field, suggestion logic fix, modal form, activity navigation
...
- Add source column to worklog_entries (migration 014): manual/suggestion/unknown
- GetSuggestions now excludes only events linked in worklog_entry_events,
not entire nodes — repeated activity same day now produces suggestions
- Manual entry form replaced with '+' button + modal dialog
- Source display shows correct origin (manual/suggestion/unknown/no-events)
- Include-children checkbox hidden when no node selected
- Activity events navigate to specific notes/files instead of just case
- Expandable row reactivity fixed (journalRows/worklog reassignment)
2026-06-03 12:27:50 +08:00
mirivlad
1472bb3e6f
feat: journal UX overhaul — picker, export dialog, events, readability
...
- Sidebar i18n: added missing nav.journal to backend ru.json
- Export: SaveWorklogReport binding with native SaveFileDialog + os.WriteFile
- Filter: better IncludeChildren label with disabled tooltip
- Filter: renamed billable→К оплате, approximate→Тип времени with hints
- worklog_entry_events table (migration 013) linking entries to activity events
- Suggestion: EventIDs + Events details, expandable cards with timestamps
- Journal rows: expandable with details, source, linked events
- Contrast: improved readability for dates, timestamps, hover states
- i18n: added worklog.*, journal.*, suggest.* keys to ru.js/en.js
2026-06-03 11:24:59 +08:00
mirivlad
0b26f7e5b3
refactor: implement template-driven node tree and human-readable vault layout
...
Unified Node model: added template_id, fs_path, archived, sort_order fields.
Template registry: system templates embedded as JSON (folder/project/client/
document/recipe), with Registry for enabled/disabled/filtered access.
SafeDisplayNameToPathSegment: human-readable path segments with Cyrillic
support, illegal char replacement, uniqueness via numeric suffixes.
Sidebar refactored: system views (Today/Inbox/Activity) separate from
workspace tree. Creation menu built dynamically from enabled templates.
Create/Rename/Move: physical folder operations with fs_path update,
recursive descendant path updates.
DB migration 012: adds template_id, fs_path, archived columns.
Vault migration command: rebuilds fs_path for existing nodes.
Tests: safename, registry, node model, repository integration.
Docs: VAULT_LAYOUT.md, TEMPLATES.md, PLAN.md updated.
i18n: nav.system, nav.workspace, template.*, common.rename/archive,
migrate.* keys added to ru.json and en.json.
2026-06-02 12:47:06 +08:00
mirivlad
2fa583d157
stabilization: server.go split + i18n templates + frontend localization
...
cmd/verstak-server/server.go (2838→127 строк): разделён на 12 файлов
- config.go, tokens.go, schema.go
- server.go (только struct + NewServer + ListenAndServe)
- routes.go, middleware.go, smtp.go
- handlers_api.go, handlers_user.go, handlers_web_user.go, handlers_admin.go
- templates.go (конвертирован в функции с i18n.T())
frontend: все русские строки заменены на t() вызовы
- App.svelte, FileTreeRow.svelte, ConfirmModal.svelte
- FilePreviewModal.svelte, fileUtils.js
core: gofmt по всему проекту
Все сборки (CLI, server, gui, frontend), go vet, go test проходят.
check-i18n.sh: frontend чист, Go-файлы с кириллицей — только тесты/легаси.
2026-06-02 11:08:29 +08:00
mirivlad
87c8dfcbea
sync: overhaul sync system — device pairing, server_sequence, auto-sync, dashboards
...
BREAKING: replace legacy API keys with device tokens via pairing flow.
- Server: /api/client/pair, revoke, me endpoints; server_sequence + tombstones + idempotency
- Desktop client: PairDevice, GetMe, RevokeCurrent; auto-sync loop every 60s
- Config: device_token stored in separate file (0600), not config.yml
- Client DB: last_pull_seq migration for incremental pull
- Frontend (Svelte): settings modal with connect/disconnect/interval
- User dashboard (/dashboard): device list with status, revoke with password
- Admin dashboard (/admin/dashboard): devices table from /admin/api/devices
- CLI (cmd/verstak): updated for ServerSequence/GetState changes
- Fix: autoSyncLoop falls back to SQLite sync_state for server URL
- Fix: SyncSetInterval preserves server_url/device_id from SQLite
2026-06-02 02:26:05 +08:00
mirivlad
4145b4d74a
feat: sync — migration 010 for sync_ops and sync_state tables
2026-06-01 22:45:12 +08:00
mirivlad
3672e3133b
activity: global feed, per-case log, sidebar section, today UX
...
- migration 009: target_type, target_id, target_path columns
- new Event fields: TargetType, TargetID, TargetPath
- ListActivityFeed (paginated global), ListActivityByNode (per-case)
- all Record() callsites pass target info
- frontend: Активность sidebar section with chronological feed
- per-case Активность tab with real data (was placeholder)
- today events: clickable, target-type badges, event counts
2026-06-01 02:53:56 +08:00
mirivlad
c74fa3ad43
today dashboard: activity_events, ListTodayView with events timeline, frontend TodayDashboard separated from sidebar
2026-06-01 02:16:13 +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
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
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