Commit Graph
21 Commits
Author SHA1 Message Date
mirv db869a7c97 docs: update AGENTS.md with Wails []string fix, event link validation, openActivityTarget 2026-06-03 16:00:54 +08:00
mirv b42aa35ee8 fix: bypass Wails v2 []string marshalling via JSON.stringify + end-to-end test
Root cause: Wails v2.12.0 cannot reliably marshal []string arguments
from JavaScript to Go when called through positional binding.
The event IDs array arrived empty on the Go side, causing no
worklog_entry_events INSERTs.

Fix:
- AcceptSuggestionWith now accepts eventIDsJSON (string) instead of
  eventIDs ([]string). Frontend passes JSON.stringify(eventIds).
- Backend json.Unmarshal into []string before validation.
- Pre-insert validation: each eventID checked in activity_events.
- Atomic tx: entry create + linking in single Begin/Commit.
- INSERT (not INSERT OR IGNORE) — failure is a hard error.
- Post-commit verification: JOIN COUNT(*) must match len(eventIDs).
- End-to-end test: TestAcceptSuggestionWithEndToEnd creates a node,
  3 activity events, accepts suggestion, verifies all 3 linked.

Other changes:
- GetWorklogEntryEvents: fixed column name (details_json -> metadata).
- openActivityTarget(ev): new function for 'Посмотреть' button that
  navigates to specific note/file/folder instead of just opening node.
- All 'openNodeById(ev.nodeId)' in event contexts replaced with
  'openActivityTarget(ev)'.
2026-06-03 16:00:17 +08:00
mirv 21a595c3ce fix: transaction-safe AcceptSuggestionWith + safe eventIds fallback + debug logging
Root cause: s.eventIds may be undefined in JavaScript even when s.events
has data (Wails v2 marshalling of []string in nested struct response).
On calling AcceptSuggestionWith(eventIDs []string), empty array reached Go,
no INSERTs executed, events silently lost.

Changes:
- Frontend: extractEventIds() fallback — s.eventIds || s.events[].id || []
- Frontend: console.log debug for eventIds/events in accept handler
- Backend: AcceptSuggestionWith wrapped in tx (Begin/Commit/Rollback) so
  entry creation + event linking is atomic
- Backend: AddWithSourceTx method for transaction-aware insert
- Backend: buildEntry helper extracted
- Backend: fmt.Printf debug logging for received eventIDs + link count
- Backend: verification query after commit
- Cleanup: removed stale frontend-dist assets, .gitignore build.log
2026-06-03 15:10:25 +08:00
mirv 7076980954 fix: AcceptSuggestionWith uses flat fields to avoid Wails marshalling issues; human-readable event labels
- AcceptSuggestionWith now accepts nodeID, summary, minutes, date, eventIDs
  as separate args instead of the entire Suggestion struct (Wails v2 skips
  nested struct fields during JS→Go marshalling)
- Error handling: event link failures now return an error instead of silent ignore
- Event type labels in suggestion detail and journal row detail now use
  eventLabel() which maps snake_case types to human-readable i18n labels
  (e.g. note_updated → 'Заметка изменена')
- Added missing event labels: note_deleted, node_deleted, folder_moved,
  action_created, action_done, worklog_added
2026-06-03 12:35:13 +08:00
mirv 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
mirv 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
mirv d34100e2ed feat: node search picker, ByNode grouping fix, PDF export
- node picker: Search/Path on Repository, SearchNodes binding,
  debounced search dropdown showing title + full path
- ByNode summary groups by nodeID with NodePath as label (not NodeTitle)
- PDF export for worklog reports with embedded DejaVuSans fonts
- ExportWorklogPDF binding + button on Journal screen
- Removed unused Section field from ReportFilter
- ListReport now calls BuildReportPaths so nodePath is available
- go.sum: +github.com/signintech/gopdf dependency
2026-06-03 10:56:13 +08:00
mirv 5732264fc5 fix(step16.1): review fixes — acceptance, filters, sorting, export
- Remove dead acceptSuggestion, unify into refreshAfterSuggestion()
- Journal: nodeID picker, includeChildren only with selected node
- Journal: billable/approximate filters (all/yes/no selects)
- Summary: ByDay sorted by date desc, ByNode by minutes desc
- CSV: proper encoding/csv writer (was manual fmt.Sprintf)
- Markdown: escape pipes and newlines via escMD()
- After suggestion: refresh suggestions + count + worklog + journal
- Add GetNodeTitle binding
- i18n: common.all/no/date/search
2026-06-03 10:30:48 +08:00
mirv c25e75f839 Step 16.1: global worklog dashboard + conservative suggestions
- Fix date timezone: worklog.Add uses local date (was UTC)
- Conservative suggestion estimator:
  - burst detection (10min window), time spread analysis
  - 5-30 min range, 60+ only with strong evidence
  - confidence levels: low/medium/high with reason
- worklog/report.go: ReportFilter, ListReport, Summary, ExportCSV, ExportMarkdown
- Expanded WorklogDTO: date, details, approximate, billable, nodeTitle
- New bindings: CreateWorklogFull, ListWorklogReport, WorklogSummary, Export*
- New system section 'Журнал' in sidebar with badge (suggestion count)
- Global journal screen: filters (date range, includeChildren), table, summary
- Suggestions shown on Today dashboard + Journal screen + per-node worklog tab
- Suggestion cards: editable minutes, confidence display, apply/open buttons
- i18n: all new keys in ru + en
2026-06-03 09:56:17 +08:00
mirv 57d13c9506 feat: activity-based worklog suggestions (Step 16)
- Suggestion struct with nodeId, nodeTitle, summary, suggestedMin
- GetSuggestions binding: analyzes today's activity events, groups by
  node, skips nodes with existing today's worklog, generates summary
- AcceptSuggestion binding: creates worklog entry from suggestion
- HasTodayEntries helper on worklog.Service
- Suggestions panel in Worklog tab with Apply button
- i18n: worklog.suggestions / worklog.apply (ru + en)
2026-06-03 09:31:40 +08:00
mirv ca280a59c0 test: comprehensive sync package unit tests (37 new tests)
- safe_path_test.go: path traversal protection (11 table-driven cases)
- blob_test.go: SHA-256 hashing, store/deduplicate/read blobs
- sync_test.go: Service CRUD ops, state, push/mark lifecycle
- client_test.go: Push/Pull/Blobs/Auth via httptest.Server
- sync_e2e_test.go: auto-build server binary on demand
2026-06-03 09:16:38 +08:00
mirv 7d81250ebd fix: rename node not found, A11y warnings cleanup
- fix renameId cleared before RenameNode API call (submitRename)
- add role, tabindex, keydown handlers to all interactive divs
- associate labels with inputs (wrap in label + .label-text)
- remove autofocus, unused CSS selectors, old root build.sh
- update frontend-dist assets
2026-06-03 08:55:38 +08:00
mirv 20a05569ac fix: второй стабилизационный pass vault layout — sync payload, bindings, vaultPath, tests
sync_apply.go:
- applyRemoteNodeCreate: полный payload (template_id/fs_path/sort_order/archived),
  INSERT сохраняет все поля, для folder-like создаётся физическая папка.
- applyRemoteNodeUpdate: принимает fs_path/template_id/archived,
  физическое переименование папки при изменении title/fs_path.
- applyRemoteNodeMove: принимает fs_path, обновляет parent_id+fs_path,
  физически перемещает папку (folder-like) или file record (note/file).

bindings_nodes.go:
- MoveNode: node.FsPath = newFsPath после UpdateFsPath;
  sync.RecordOp отправляет новый fs_path; note/file move to root — файл в vault root.
- RenameNode: EntityFile для file, EntityNote для note;
  коллизия → генерация уникального имени; файл переименовывается только после os.Rename.
- DeleteNode: единый вызов a.files.DeleteNodeAndChildren(), дублирование удалено.
- Исправлен deadlock с SetMaxOpenConns(1) — Query/Exec больше не конфликтуют.

files.Service.vaultPath: filepath.Rel-based проверка,
  sibling-prefix escape (/tmp/vault vs /tmp/vault_evil) отклоняется.

VaultCheck: SQL JOIN с n.deleted_at IS NULL, чтобы удалённые узлы
  не показывались как missing files.

Добавлены тесты: RenameFileNodeUsesEntityFile, MoveNoteToRoot,
  DeleteFolderLeavesVaultCheckHealthy, SyncNodeCreatePreservesFields,
  VaultPathSiblingPrefixEscape.
2026-06-02 17:03:05 +08:00
mirv 66c5c81f39 fix: стабилизация vault layout — rename/move/delete note/file vs folder разведены, sync apply без spaces/, VaultCheck усилен
- RenameNode/DeleteNode/MoveNode: note/file и folder-like nodes
  обрабатываются по-разному (file record vs физическая папка)
- DeleteNode: рекурсивный soft-delete всех descendants
- SafeVaultPath возвращает clean relative, filepath.Join в sync_apply.go
- Fallback spaces/ → .verstak/remote-inbox в applyRemoteNoteCreate
- VaultCheck: проверка parent_id != nil, orphan descendants,
  fs_path folder на диске
2026-06-02 16:36:43 +08:00
mirv 4f01f2de2e fix: complete vault layout transition — fs_path everywhere, no more spaces/
- notes.Create(): .md files stored in parent node's fs_path folder
- files.CopyIntoVault/CreateEmptyFile/Duplicate: use parent fs_path
- files.AddPathCopy/AddPathLink: use parent fs_path, set folder fs_path
- files.DeleteNodeAndChildren: move physical folder to .verstak/trash
- UpdateFsPathRecursive: use SafeDisplayNameToPathSegment(child.Title)
- sync_apply.go note ops: use fs_path instead of spaces/
- internal/gui/server.go file upload: use n.FsPath instead of nodeSlug
- VaultCheck diagnostic: walk nodes/files, verify paths on disk
- Tests: create/rename/move/delete/name-conflict/vault-check all pass
2026-06-02 15:43:40 +08:00
mirv 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
mirv 12f2916a24 followup: SafeVaultPath in note update, email i18n, strict check-i18n.sh
- applyRemoteNoteUpdate: use SafeVaultPath for vault mode, skip non-vault with log
- Email subjects/bodies moved to Go i18n (confirm + reset) in ru.json and en.json
- check-i18n.sh: ru/en key mismatch now FAIL (not WARNING)
- All builds, tests, frontend pass
2026-06-02 11:40:27 +08:00
mirv 7091397649 server i18n: move inline HTML to templates.go, localize all handler strings
- Admin & user dashboard HTML moved from handlers to templates.go with i18n.T()
- SafeVaultPath applied in sync_apply.go (note/file create/update, blob restore)
- DeleteNode/RenameNode/MoveNode fixed: correct activity type / entity variant
- Added TypeNoteDeleted, TypeNodeDeleted, TypeFolderMoved activity constants
- Added locale() helper on Server struct, removed hardcoded 'ru' in handlers
- Password policy loosened: 8-256 chars, any characters, machine-readable error codes
- check-i18n.sh: Go Cyrillic = FAIL with explicit exception list, Go locale key consistency check
2026-06-02 11:26:54 +08:00
mirv 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
mirv 3089d777a8 refactor(gui): разделить app.go на binding-файлы по доменам, вынести sync apply
- app.go (1810→280 строк): только App struct, startup, DTOs, helpers
- bindings_{nodes,files,notes,actions,worklog,activity,sync,settings}.go
- sync_apply.go: все applyRemote* методы
- i18n: internal/i18n (Go, embed JSON) + frontend/src/lib/i18n (JS)
- core/sync/safe_path.go: SafeVaultPath
- scripts/check-i18n.sh: проверка хардкода кириллицы и bidi-символов
- build.sh: NVM loading, set -e

Все сборки (CLI, server, gui, frontend), go vet, go test проходят.
2026-06-02 10:47:38 +08:00
mirv 390d451977 frontend: удалён мёртвый код (verstak.js, FileActions.svelte, style.css) 2026-06-02 09:48:58 +08:00