diff --git a/docs/frontend-architecture.md b/docs/frontend-architecture.md
new file mode 100644
index 0000000..6d2813a
--- /dev/null
+++ b/docs/frontend-architecture.md
@@ -0,0 +1,143 @@
+# Frontend Architecture
+
+## Overview
+
+Verstak frontend is a Svelte 3 application running inside Wails v2 (Go bridge).
+The app manages a hierarchical vault of nodes (folders/cases, notes, files, links, actions)
+with sync capabilities, worklog/journal, and activity tracking.
+
+## Technology Stack
+
+- **UI Framework:** Svelte 3 (plain JS, no TypeScript in components)
+- **Desktop Bridge:** Wails v2 (`window.go.main.App.*`)
+- **Bundler:** Vite (via Wails)
+- **Markdown:** Custom renderer in `lib/markdown/`
+- **i18n:** Custom lightweight system in `lib/i18n/`
+- **Styling:** Scoped CSS in Svelte components, dark theme
+
+## Directory Structure
+
+```
+frontend/src/
+├── App.svelte # Root component (being modularised)
+├── TreeNode.svelte # Tree node for sidebar (inline)
+├── FileTreeRow.svelte # File row in file tab (inline)
+├── wailsjs/go/main/App.js # Auto-generated Wails bindings
+├── lib/
+│ ├── components/ # Reusable UI components
+│ │ └── notes/
+│ │ ├── NoteEditorPanel.svelte
+│ │ ├── MarkdownEditor.svelte
+│ │ ├── MarkdownPreview.svelte
+│ │ ├── InternalLinkPicker.svelte
+│ │ └── ObjectPickerModal.svelte
+│ ├── services/ # API/Data access layer
+│ │ ├── wails.js # Base Wails call helper
+│ │ ├── notes.js # Notes API
+│ │ ├── files.js # Files API
+│ │ ├── search.js # Search API
+│ │ ├── inbox.js # Inbox API
+│ │ ├── trash.js # Trash API
+│ │ ├── sync.js # Sync API
+│ │ ├── journal.js # Journal/Worklog API
+│ │ ├── actions.js # Actions API
+│ │ ├── links.js # Links API
+│ │ └── activity.js # Activity API
+│ ├── state/ # State management (planned)
+│ │ ├── navigation.js # Navigation state
+│ │ └── uiState.js # UI state
+│ ├── markdown/ # Markdown processing
+│ │ ├── markdown.ts
+│ │ └── internalLinks.ts
+│ ├── i18n/ # Internationalisation
+│ │ ├── index.js
+│ │ └── locales/
+│ │ ├── en.js
+│ │ └── ru.js
+│ ├── util/ # Utilities
+│ │ ├── keyboardLayout.ts
+│ │ └── markdown.test.js
+│ ├── AppHeader.svelte
+│ ├── GlobalSearch.svelte
+│ ├── FileBreadcrumbs.svelte
+│ ├── FileIcon.svelte
+│ ├── FilePreviewModal.svelte
+│ ├── ConfirmModal.svelte
+│ ├── TodayScreen.svelte
+│ ├── BrowserEvents.svelte
+│ ├── FirstRun.svelte
+│ ├── VaultRecovery.svelte
+│ ├── SyncStatus.svelte
+│ ├── TemplateIcon.svelte
+│ ├── CalendarPluginPage.svelte
+│ ├── SettingsWindow.svelte
+│ ├── SettingsSidebar.svelte
+│ ├── SettingsGeneral.svelte
+│ ├── SettingsSync.svelte
+│ ├── SettingsPlugins.svelte
+│ ├── SettingsBrowserBridge.svelte
+│ ├── SettingsWorkspace.svelte
+│ ├── SettingsTemplates.svelte
+│ ├── SettingsFiles.svelte
+│ ├── SettingsBackup.svelte
+│ ├── SettingsActivity.svelte
+│ ├── actionIcons.js
+│ └── fileUtils.js
+```
+
+## Wails Bridge
+
+All backend calls go through `window.go.main.App[method](...)`.
+The `wailsCall()` helper in `lib/services/wails.js` provides error handling.
+
+## Planned Components (to extract from App.svelte)
+
+### Layout
+- `AppShell.svelte` — root layout wrapper
+- `Sidebar.svelte` — navigation sidebar
+- `MainWorkspace.svelte` — main content area
+
+### Pages/Tab Content
+- `OverviewTab.svelte` — node overview with meta and quick actions
+- `NotesTab.svelte` — notes list and creation
+- `FilesTab.svelte` — file browser with breadcrumbs
+- `InboxContent.svelte` + `InboxFullScreen.svelte`
+- `LinksTab.svelte`
+- `ActionsTab.svelte`
+- `WorklogTab.svelte`
+- `ActivityTabContent.svelte`
+- `TrashContent.svelte`
+- `JournalScreen.svelte`
+- `ActivityFeedScreen.svelte`
+- `WelcomeScreen.svelte`
+
+### Modals
+- `CreateNodeModal.svelte`
+- `WorklogModal.svelte`
+- `CreateActionModal.svelte`
+- `ImportModal.svelte`
+- `RenameModal.svelte`
+- `AssignInboxModal.svelte`
+- `EditLinkModal.svelte`
+- `LinkInsertModal.svelte`
+- `NoteRenameModal.svelte`
+- `ContextMenu.svelte`
+
+## Data Flow
+
+1. User interacts with UI component
+2. Component calls a service function (e.g., `notesApi.createNote(...)`)
+3. Service calls `wailsCall('CreateNote', ...)`
+4. Wails bridge forwards to Go backend
+5. Go backend returns result → Wails → service → component updates state
+
+## State Management
+
+Currently all state lives in App.svelte as local variables.
+Target: extract into `lib/state/navigation.js` and `lib/state/uiState.js`.
+
+## Build & Verification
+
+- `npm run build` in `frontend/` directory
+- `go test ./...` from project root
+- Manual smoke testing via Wails dev server
diff --git a/docs/frontend-change-map.md b/docs/frontend-change-map.md
new file mode 100644
index 0000000..0e4c8bc
--- /dev/null
+++ b/docs/frontend-change-map.md
@@ -0,0 +1,95 @@
+# Frontend Change Map
+
+## Purpose
+
+This document tracks the refactoring of `App.svelte` from a 4794-line monolith
+into a modular frontend architecture. Each step preserves behaviour exactly.
+
+## Phase 1: Documentation & Foundation
+
+- [x] Audit App.svelte (all 4794 lines read and mapped)
+- [x] Create `docs/frontend-architecture.md`
+- [x] Create `docs/frontend-change-map.md`
+
+## Phase 2: API Layer
+
+Extract all Wails calls into service modules.
+
+- [ ] Create `lib/services/wails.js` — base `wailsCall` helper
+- [ ] Create `lib/services/notes.js` — `listNotes`, `createNote`, `readNote`, `saveNote`, `renameNote`, `deleteNote`
+- [ ] Create `lib/services/files.js` — `loadFolder`, `addFile`, `deleteFile`, etc.
+- [ ] Create `lib/services/search.js` — `searchNodes`
+- [ ] Create `lib/services/inbox.js` — `listInbox`, `captureClipboard`, etc.
+- [ ] Create `lib/services/trash.js` — `loadTrash`, `restore`, `purge`
+- [ ] Create `lib/services/sync.js` — `loadSyncStatus`, `runSync`
+- [ ] Create `lib/services/journal.js` — `loadJournal`, `worklog CRUD`
+- [ ] Create `lib/services/actions.js` — `listActions`, `createAction`, `deleteAction`
+- [ ] Create `lib/services/links.js` — `listLinks`, `updateLink`, `deleteLink`
+- [ ] Create `lib/services/activity.js` — `loadActivityFeed`, `loadCaseActivity`
+
+## Phase 3: State Extraction
+
+- [ ] Create `lib/state/navigation.js` — `selectedSection`, `selectedNode`, `activeTab`, `navHistory`
+- [ ] Create `lib/state/uiState.js` — modals state, confirm state, rename state, drag state
+
+## Phase 4: Component Extraction — Layout
+
+- [ ] Extract `Sidebar.svelte` — brand, nav items, workspace tree, footer
+- [ ] Extract `MainWorkspace.svelte` — content routing
+- [ ] Create `AppShell.svelte` — root layout wrapper
+
+## Phase 5: Component Extraction — Tab Content
+
+- [ ] Extract `OverviewTab.svelte`
+- [ ] Extract `NotesTab.svelte`
+- [ ] Extract `FilesTab.svelte`
+- [ ] Extract `LinksTab.svelte`
+- [ ] Extract `ActionsTab.svelte`
+- [ ] Extract `WorklogTab.svelte`
+- [ ] Extract `ActivityTabContent.svelte`
+- [ ] Extract `InboxContent.svelte`
+- [ ] Extract `InboxFullScreen.svelte`
+- [ ] Extract `TrashContent.svelte`
+- [ ] Extract `JournalScreen.svelte`
+- [ ] Extract `ActivityFeedScreen.svelte`
+- [ ] Extract `WelcomeScreen.svelte`
+
+## Phase 6: Component Extraction — Modals
+
+- [ ] Extract `CreateNodeModal.svelte`
+- [ ] Extract `WorklogModal.svelte`
+- [ ] Extract `CreateActionModal.svelte`
+- [ ] Extract `ImportModal.svelte`
+- [ ] Extract `RenameModal.svelte`
+- [ ] Extract `AssignInboxModal.svelte`
+- [ ] Extract `EditLinkModal.svelte`
+- [ ] Extract `ContextMenu.svelte`
+
+## Phase 7: Extract Inline Components
+
+- [ ] Extract `NoteEditorHeader.svelte` (note editor header with rename)
+- [ ] Extract `ErrorBanner.svelte`
+- [ ] Extract `CaptureDropOverlay.svelte`
+- [ ] Extract `SidebarFooter.svelte`
+
+## Phase 8: Verification
+
+- [ ] `npm run build` passes
+- [ ] `go test ./...` passes
+- [ ] Smoke checklist:
+ 1. Sidebar renders with system views
+ 2. Workspace tree loads and is expandable
+ 3. Selecting a node shows tabs
+ 4. Overview tab shows metadata and quick actions
+ 5. Notes tab — create, rename, delete notes
+ 6. Note editor — edit, preview, save, internal links, external links
+ 7. Files tab — browse, add file/folder, navigate breadcrumbs
+ 8. File preview — open, close
+ 9. Inbox — list, sort, group, assign, delete
+ 10. Trash — browse, restore, purge
+ 11. Journal — filter, export, worklog CRUD
+ 12. Activity feed — load and open events
+ 13. Today screen — dashboard, suggestions, browser events
+ 14. Settings — open/close, sections
+ 15. Context menu on workspace tree
+ 16. Create node modal — templates
diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte
index 5934ef0..042b836 100644
--- a/frontend/src/App.svelte
+++ b/frontend/src/App.svelte
@@ -18,6 +18,10 @@
import { t } from './lib/i18n'
import NoteEditorPanel from './lib/components/notes/NoteEditorPanel.svelte'
import InternalLinkPicker from './lib/components/notes/InternalLinkPicker.svelte'
+ import ErrorBanner from './lib/components/ErrorBanner.svelte'
+ import CaptureDropOverlay from './lib/components/CaptureDropOverlay.svelte'
+ import OverviewTab from './lib/components/OverviewTab.svelte'
+ import NotesTab from './lib/components/notes/NotesTab.svelte'
// ===== Wails v2 API call helper =====
function wailsCall(method, ...args) {
@@ -2845,11 +2849,7 @@
{:else}
- {#if captureDropActive}
-
- {/if}
+
{#if activeTab === 'overview'}
-
-
{selectedNode.title}
-
-
-
-
-
-
-
- {#if notes.length > 0}
-
-
{t('overview.recentNotes')}
- {#each notes.slice(0, 5) as note}
-
openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}>
- {note.title}{formatDate(note.createdAt)}
-
- {/each}
-
- {/if}
- {#if worklog.length > 0}
-
-
{t('overview.recentEntries')}
- {#each worklog.slice(0, 3) as e}
-
{e.summary} ({e.minutes} {t('worklog.min')})
- {/each}
-
- {/if}
-
+
setActiveTab(e.detail)}
+ on:openNote={(e) => openNote(e.detail.note)}
+ on:createNote={() => { setActiveTab('notes'); openCreateNote() }}
+ on:addFile={() => { setActiveTab('files'); addFile() }}
+ on:createAction={openCreateAction}
+ />
{:else if activeTab === 'notes'}
-
-
-
-
- {#if showCreateNote}
-
- {/if}
- {#if notes.length === 0 && !showCreateNote}
-
{t('note.noNotes')}
{t('note.createFirst')}
- {:else}
-
- {#each notes as note}
-
openNote(note)} on:keydown={onKeyActivate(() => openNote(note))}>
-
-
{note.title}
-
{formatDate(note.createdAt)}
-
-
-
-
-
-
- {/each}
-
- {/if}
-
+ { newNoteTitle = e.detail.title; submitCreateNote() }}
+ on:cancelCreateNote={cancelCreateNote}
+ on:openNote={(e) => openNote(e.detail.note)}
+ on:startRename={(e) => startRenameNote(e.detail.note.id, e.detail.note.title)}
+ on:delete={(e) => deleteNote(e.detail.note)}
+ />
{:else if activeTab === 'files'}
diff --git a/frontend/src/lib/components/CaptureDropOverlay.svelte b/frontend/src/lib/components/CaptureDropOverlay.svelte
new file mode 100644
index 0000000..a521e7f
--- /dev/null
+++ b/frontend/src/lib/components/CaptureDropOverlay.svelte
@@ -0,0 +1,15 @@
+
+
+{#if show}
+
+{/if}
+
+
diff --git a/frontend/src/lib/components/ErrorBanner.svelte b/frontend/src/lib/components/ErrorBanner.svelte
new file mode 100644
index 0000000..d28ea3e
--- /dev/null
+++ b/frontend/src/lib/components/ErrorBanner.svelte
@@ -0,0 +1,37 @@
+
+
+{#if error}
+
+ {translateError(error)}
+
+
+{/if}
+
+
diff --git a/frontend/src/lib/components/OverviewTab.svelte b/frontend/src/lib/components/OverviewTab.svelte
new file mode 100644
index 0000000..7b7b636
--- /dev/null
+++ b/frontend/src/lib/components/OverviewTab.svelte
@@ -0,0 +1,98 @@
+
+
+
+
{node.title}
+
+
+
+
+
+
+
+
+
+ {#if notes.length > 0}
+
+
{t('overview.recentNotes')}
+ {#each notes.slice(0, 5) as note}
+
dispatch('openNote', { note })} on:keydown={onKeyActivate(() => dispatch('openNote', { note }))}>
+ {note.title}{formatDate(note.createdAt)}
+
+ {/each}
+
+ {/if}
+
+ {#if worklog.length > 0}
+
+
{t('overview.recentEntries')}
+ {#each worklog.slice(0, 3) as e}
+
{e.summary} ({e.minutes} {t('worklog.min')})
+ {/each}
+
+ {/if}
+
+
+
diff --git a/frontend/src/lib/components/notes/NotesTab.svelte b/frontend/src/lib/components/notes/NotesTab.svelte
new file mode 100644
index 0000000..5660b57
--- /dev/null
+++ b/frontend/src/lib/components/notes/NotesTab.svelte
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+ {#if showCreateNote}
+
+ {/if}
+ {#if notes.length === 0 && !showCreateNote}
+
{t('note.noNotes')}
{t('note.createFirst')}
+ {:else}
+
+ {#each notes as note}
+
handleOpenNote(note)} on:keydown={onKeyActivate(() => handleOpenNote(note))}>
+
+
{note.title}
+
{formatDate(note.createdAt)}
+
+
+
+
+
+
+ {/each}
+
+ {/if}
+
+
+
diff --git a/frontend/src/lib/services/actions.js b/frontend/src/lib/services/actions.js
new file mode 100644
index 0000000..cb42afd
--- /dev/null
+++ b/frontend/src/lib/services/actions.js
@@ -0,0 +1,9 @@
+/**
+ * Actions API — actions (quick commands) on nodes.
+ */
+import { createApi } from './wails.js'
+
+export const listActions = createApi('ListActions')
+export const createAction = createApi('CreateAction')
+export const runAction = createApi('RunAction')
+export const deleteAction = createApi('DeleteAction')
diff --git a/frontend/src/lib/services/activity.js b/frontend/src/lib/services/activity.js
new file mode 100644
index 0000000..195071d
--- /dev/null
+++ b/frontend/src/lib/services/activity.js
@@ -0,0 +1,7 @@
+/**
+ * Activity API — activity feed and per-node activity.
+ */
+import { createApi } from './wails.js'
+
+export const listActivityFeed = createApi('ListActivityFeed')
+export const listActivityByNode = createApi('ListActivityByNode')
diff --git a/frontend/src/lib/services/browserEvents.js b/frontend/src/lib/services/browserEvents.js
new file mode 100644
index 0000000..50b457c
--- /dev/null
+++ b/frontend/src/lib/services/browserEvents.js
@@ -0,0 +1,9 @@
+/**
+ * Browser Events API — browser extension events.
+ */
+import { createApi } from './wails.js'
+
+export const listBrowserEvents = createApi('ListBrowserEvents')
+export const acceptBrowserEvent = createApi('AcceptBrowserEvent')
+export const dismissBrowserEvent = createApi('DismissBrowserEvent')
+export const attachBrowserEventToNode = createApi('AttachBrowserEventToNode')
diff --git a/frontend/src/lib/services/files.js b/frontend/src/lib/services/files.js
new file mode 100644
index 0000000..c43be5d
--- /dev/null
+++ b/frontend/src/lib/services/files.js
@@ -0,0 +1,20 @@
+/**
+ * Files API — all file/folder related Wails calls.
+ */
+import { createApi } from './wails.js'
+
+export const listItems = createApi('ListItems')
+export const listFiles = createApi('ListFiles')
+export const createEmptyFile = createApi('CreateEmptyFile')
+export const deleteFileOrFolder = createApi('DeleteFileOrFolder')
+export const openFile = createApi('OpenFile')
+export const openFolder = createApi('OpenFolder')
+export const pickFile = createApi('PickFile')
+export const pickDirectory = createApi('PickDirectory')
+export const previewImport = createApi('PreviewImport')
+export const addPathCopy = createApi('AddPathCopy')
+export const addPathLink = createApi('AddPathLink')
+export const checkFileAction = createApi('CheckFileAction')
+export const getFileBase64 = createApi('GetFileBase64')
+export const readFileText = createApi('ReadFileText')
+export const showInFolder = createApi('OpenFolder')
diff --git a/frontend/src/lib/services/inbox.js b/frontend/src/lib/services/inbox.js
new file mode 100644
index 0000000..8ff125b
--- /dev/null
+++ b/frontend/src/lib/services/inbox.js
@@ -0,0 +1,14 @@
+/**
+ * Inbox API — capture and inbox management.
+ */
+import { createApi } from './wails.js'
+
+export const listInboxNodes = createApi('ListInboxNodes')
+export const listInboxNodesForTarget = createApi('ListInboxNodesForTarget')
+export const captureClipboardTextWithContext = createApi('CaptureClipboardTextWithContext')
+export const captureTextWithContext = createApi('CaptureTextWithContext')
+export const captureURLWithContext = createApi('CaptureURLWithContext')
+export const capturePathWithContext = createApi('CapturePathWithContext')
+export const captureFileDataWithContext = createApi('CaptureFileDataWithContext')
+export const resolveInboxNode = createApi('ResolveInboxNode')
+export const deleteInboxNode = createApi('DeleteInboxNode')
diff --git a/frontend/src/lib/services/journal.js b/frontend/src/lib/services/journal.js
new file mode 100644
index 0000000..5960b4b
--- /dev/null
+++ b/frontend/src/lib/services/journal.js
@@ -0,0 +1,13 @@
+/**
+ * Journal & Worklog API — time tracking and reporting.
+ */
+import { createApi } from './wails.js'
+
+export const listWorklog = createApi('ListWorklog')
+export const createWorklogFull = createApi('CreateWorklogFull')
+export const updateWorklogEntry = createApi('UpdateWorklogEntry')
+export const deleteWorklogEntry = createApi('DeleteWorklogEntry')
+export const getWorklogEntryEvents = createApi('GetWorklogEntryEvents')
+export const listWorklogReport = createApi('ListWorklogReport')
+export const worklogReportSummary = createApi('WorklogReportSummary')
+export const saveWorklogReport = createApi('SaveWorklogReport')
diff --git a/frontend/src/lib/services/links.js b/frontend/src/lib/services/links.js
new file mode 100644
index 0000000..0052bd2
--- /dev/null
+++ b/frontend/src/lib/services/links.js
@@ -0,0 +1,9 @@
+/**
+ * Links API — external URL links management.
+ */
+import { createApi } from './wails.js'
+
+export const listLinks = createApi('ListLinks')
+export const updateLink = createApi('UpdateLink')
+export const deleteLink = createApi('DeleteLink')
+export const openLink = createApi('OpenLink')
diff --git a/frontend/src/lib/services/nodes.js b/frontend/src/lib/services/nodes.js
new file mode 100644
index 0000000..e2abadf
--- /dev/null
+++ b/frontend/src/lib/services/nodes.js
@@ -0,0 +1,20 @@
+/**
+ * Node & Workspace API — tree, node CRUD, system views.
+ */
+import { createApi } from './wails.js'
+
+export const getStartupStatus = createApi('GetStartupStatus')
+export const verstakVersion = createApi('VerstakVersion')
+export const listSystemViewsWithPlugins = createApi('ListSystemViewsWithPlugins')
+export const listWorkspaceTree = createApi('ListWorkspaceTree')
+export const listWorkspaceChildren = createApi('ListWorkspaceChildren')
+export const listEnabledTemplates = createApi('ListEnabledTemplates')
+export const createNodeFromTemplate = createApi('CreateNodeFromTemplate')
+export const deleteNode = createApi('DeleteNode')
+export const renameNode = createApi('RenameNode')
+export const moveNode = createApi('MoveNode')
+export const duplicateNode = createApi('DuplicateNode')
+export const getNodeDetail = createApi('GetNodeDetail')
+export const getSuggestions = createApi('GetSuggestions')
+export const validateName = createApi('ValidateName')
+export const writeDebugLog = createApi('WriteDebugLog')
diff --git a/frontend/src/lib/services/notes.js b/frontend/src/lib/services/notes.js
new file mode 100644
index 0000000..58ed300
--- /dev/null
+++ b/frontend/src/lib/services/notes.js
@@ -0,0 +1,11 @@
+/**
+ * Notes API — all note-related Wails calls.
+ */
+import { createApi } from './wails.js'
+
+export const listNotes = createApi('ListNotes')
+export const createNote = createApi('CreateNote')
+export const readNote = createApi('ReadNote')
+export const saveNote = createApi('SaveNote')
+export const renameNote = createApi('RenameNote')
+export const deleteNoteApi = createApi('DeleteNote')
diff --git a/frontend/src/lib/services/search.js b/frontend/src/lib/services/search.js
new file mode 100644
index 0000000..6587074
--- /dev/null
+++ b/frontend/src/lib/services/search.js
@@ -0,0 +1,8 @@
+/**
+ * Search API — global search and node lookup.
+ */
+import { createApi } from './wails.js'
+
+export const searchNodes = createApi('SearchNodes')
+export const getNodeDetail = createApi('GetNodeDetail')
+export const searchWorkspace = createApi('SearchWorkspace')
diff --git a/frontend/src/lib/services/suggestions.js b/frontend/src/lib/services/suggestions.js
new file mode 100644
index 0000000..9a92859
--- /dev/null
+++ b/frontend/src/lib/services/suggestions.js
@@ -0,0 +1,9 @@
+/**
+ * Suggestions API — worklog suggestions.
+ */
+import { createApi } from './wails.js'
+
+export const getSuggestions = createApi('GetSuggestions')
+export const acceptSuggestionFull = createApi('AcceptSuggestionFull')
+export const dismissSuggestion = createApi('DismissSuggestion')
+export const acceptSuggestionWith = createApi('AcceptSuggestionWith')
diff --git a/frontend/src/lib/services/sync.js b/frontend/src/lib/services/sync.js
new file mode 100644
index 0000000..04319ce
--- /dev/null
+++ b/frontend/src/lib/services/sync.js
@@ -0,0 +1,7 @@
+/**
+ * Sync API — vault synchronisation.
+ */
+import { createApi } from './wails.js'
+
+export const syncStatus = createApi('SyncStatus')
+export const syncNow = createApi('SyncNow')
diff --git a/frontend/src/lib/services/today.js b/frontend/src/lib/services/today.js
new file mode 100644
index 0000000..95a3f50
--- /dev/null
+++ b/frontend/src/lib/services/today.js
@@ -0,0 +1,8 @@
+/**
+ * Today API — today dashboard, in-progress items, captures.
+ */
+import { createApi } from './wails.js'
+
+export const listTodayView = createApi('ListTodayView')
+export const listTodayInProgress = createApi('ListTodayInProgress')
+export const listTodayCaptures = createApi('ListTodayCaptures')
diff --git a/frontend/src/lib/services/trash.js b/frontend/src/lib/services/trash.js
new file mode 100644
index 0000000..8405032
--- /dev/null
+++ b/frontend/src/lib/services/trash.js
@@ -0,0 +1,12 @@
+/**
+ * Trash API — trash operations.
+ */
+import { createApi } from './wails.js'
+
+export const listTrash = createApi('ListTrash')
+export const trashCount = createApi('TrashCount')
+export const readTrashFile = createApi('ReadTrashFile')
+export const readTrashFileContent = createApi('ReadTrashFileContent')
+export const restoreTrashNodes = createApi('RestoreTrashNodesJSON')
+export const purgeTrashNodes = createApi('PurgeTrashNodesJSON')
+export const emptyTrash = createApi('EmptyTrash')
diff --git a/frontend/src/lib/services/wails.js b/frontend/src/lib/services/wails.js
new file mode 100644
index 0000000..16cb478
--- /dev/null
+++ b/frontend/src/lib/services/wails.js
@@ -0,0 +1,27 @@
+/**
+ * Base Wails API call helper.
+ * All backend communication goes through this function.
+ */
+
+export function wailsCall(method, ...args) {
+ try {
+ if (window['go'] && window['go']['main'] && window['go']['main']['App']) {
+ const fn = window['go']['main']['App'][method]
+ if (typeof fn === 'function') {
+ return fn(...args)
+ }
+ }
+ } catch (e) {
+ console.error('Wails call error:', method, e)
+ }
+ return Promise.reject(new Error('Wails not connected: ' + method))
+}
+
+/**
+ * Create a wrapped API function with consistent error handling.
+ */
+export function createApi(method) {
+ return (...args) => {
+ return wailsCall(method, ...args)
+ }
+}