Skip to content

Frontend Guide ​

Relevant source files

The following files were used as context for generating this wiki page:

Purpose and Scope ​

This document provides a comprehensive guide to KanStack's Vue.js frontend codebase. It covers the application structure, component hierarchy, composable-based state management, and frontend utilities. The frontend is built with Vue 3 and TypeScript, using the Composition API pattern throughout.

For details on specific subsystems, see:


Technology Stack ​

The frontend is built on the following core technologies:

TechnologyVersionPurpose
Vue.js3.5.13Reactive UI framework
TypeScript5.7.2Type-safe JavaScript
Vite5.4.14Build tool and dev server
Tauri API2.xIPC bridge to Rust backend
Vitest3.2.4Unit testing framework

Sources: package.json:15-28


Application Entry Point ​

The frontend application bootstraps through a standard Vue 3 setup:

index.html (root HTML template)
    ↓
src/main.ts (creates Vue app)
    ↓
src/App.vue (root component)

The entry point at src/main.ts:1-6 creates a Vue application instance and mounts it to the DOM. The root HTML template at index.html:1-13 provides a minimal container (<div id="app"></div>) where the Vue application renders.

Application Bootstrap Diagram:

Sources: index.html:1-13, src/main.ts:1-6


Component Hierarchy ​

The frontend uses a focused component structure with App.vue serving as the orchestrator. Components are organized into domain-specific directories under src/components/.

Component Structure Diagram:

The component hierarchy follows a strict separation:

  • App.vue (src/App.vue:1-1537): Owns all application state via composables, handles global keyboard shortcuts, coordinates menu actions, and manages workspace mutations.
  • Presentation Components: Receive data via props, emit events for user actions, contain no business logic.
  • Domain Components: Organized by domain (app/, board/, card/) for clear separation of concerns.

Sources: src/App.vue:6-9


Composable Architecture ​

KanStack uses Vue's Composition API with specialized composables that separate concerns by domain. Each composable manages a specific aspect of application state and behavior.

Composable Dependency Diagram:

Composable Responsibilities:

ComposablePrimary ResponsibilityKey Functions
useWorkspaceWorkspace state and lifecycleopenWorkspace(), selectBoard(), selectCard(), applyWorkspaceMutation()
useBoardActionsBoard and card mutationscreateCard(), moveCard(), archiveCards(), addColumn(), renameColumn()
useBoardSelectionMulti-select UI statehandleSelection(), moveSelection(), clearSelection()
useCardEditorCard editing sessionopenCard(), saveDraft(), closeEditor()
useActionHistoryUndo/redo functionalitypush(), shiftUndo(), shiftRedo(), clear()

Sources: src/App.vue:29-64


State Management Patterns ​

The frontend uses a unidirectional data flow pattern with reactive state managed through composables:

State Flow Diagram:

Mutation Pattern:

All workspace mutations follow a consistent pattern in src/App.vue:134-155:

  1. Capture State: Create a snapshot of current state for undo/redo
  2. Execute Action: Call composable function that serializes and persists changes
  3. Receive Snapshot: Backend returns updated WorkspaceSnapshot
  4. Store History: Save before/after snapshots in action history
  5. Apply Mutation: Update reactive state via applyWorkspaceMutation()

Sources: src/App.vue:29-155


Workspace State Structure ​

The useWorkspace composable maintains several key pieces of reactive state:

Workspace State Diagram:

Sources: src/App.vue:29-52


Event Flow and User Interactions ​

User interactions flow through a consistent event handling pattern:

Keyboard Shortcuts:

Global keyboard shortcuts are handled in src/App.vue:912-1108. The application distinguishes between:

  • Editable context: When focus is in an input/textarea (shortcuts disabled)
  • Global context: When focus is on the board (shortcuts enabled)

Key shortcuts include:

ShortcutActionImplementation
Cmd/Ctrl+OOpen workspaceopenWorkspaceFromMenu()
Cmd/Ctrl+NNew cardcreateCardFromBoard()
Cmd/Ctrl+Shift+NNew boardcreateBoardFromWorkspace()
Cmd/Ctrl+ZUndoundoAction()
Cmd/Ctrl+Shift+ZRedoredoAction()
Cmd/Ctrl+Shift+AToggle archivetoggleArchiveColumn()
EscapeClose/clear selectionMulti-level escape handling
EnterOpen selected cardopenSelectedCard()
Delete/BackspaceArchive cardsarchiveSelectedCards()
Shift+DeleteDelete cardsdeleteSelectedCards()
SpaceEnter move modeToggle keyboardMoveMode
Arrow keysNavigate/moveContext-dependent navigation

Keyboard Move Mode:

The application supports two keyboard move modes (src/App.vue:62, src/App.vue:975-1022):

  • Card move mode: Activated with Space when a card is selected, allows arrow key repositioning
  • Column move mode: Activated with Space when a column is selected, allows left/right reordering

Sources: src/App.vue:912-1120


The frontend integrates with Tauri's native menu system through an event listener:

Menu Action Flow:

Menu actions are registered in src/App.vue:1122-1133 and dispatched in src/App.vue:1135-1201. The dispatcher maps action strings to handler functions:

"open-folder" → openWorkspaceFromMenu()
"new-card" → createCardFromBoard()
"new-board" → createBoardFromWorkspace()
"undo-action" → undoAction()
"archive-selected-cards" → archiveSelectedCards()
...etc

Sources: src/App.vue:1122-1201


IPC Communication with Backend ​

The frontend communicates with the Rust backend through Tauri's invoke() API. All IPC calls are asynchronous and return WorkspaceSnapshot objects that represent the updated file system state.

IPC Command Patterns:

Common IPC Commands:

CommandPurposeReturn Type
load_workspaceLoad workspace from pathWorkspaceSnapshot
save_board_fileWrite board markdownWorkspaceSnapshot
save_card_fileWrite card markdownWorkspaceSnapshot
create_cardCreate new card file{slug, snapshot}
delete_card_fileDelete card fileWorkspaceSnapshot
delete_boardDelete board and descendantsWorkspaceSnapshot
apply_workspace_snapshotRestore snapshot (undo/redo)WorkspaceSnapshot

Sources: src/App.vue:3, src/App.vue:119-131, src/App.vue:709-719, src/App.vue:783-794


Undo/Redo System ​

The undo/redo system is implemented using the useActionHistory composable, which stores complete workspace snapshots for each tracked action.

Action History Structure:

Tracked Action Pattern:

The executeTrackedAction() function (src/App.vue:134-155) wraps any mutation operation:

  1. Call createHistoryStateSnapshot() to capture current state
  2. Execute the action (returns a new snapshot)
  3. Push both snapshots to action history with a label
  4. Apply the new snapshot to reactive state

Undo Operation:

Sources: src/App.vue:64, src/App.vue:99-155, src/App.vue:211-227


Multi-Select System ​

The useBoardSelection composable manages card multi-selection with keyboard and mouse support:

Selection Interaction Patterns:

InteractionBehavior
Click cardSelect single card, clear previous selection
Cmd/Ctrl+ClickToggle card in selection
Shift+ClickRange select from last selected to clicked card
Arrow keysNavigate selection in direction
Cmd/Ctrl+ASelect all visible cards

Selection State:

The selection system maintains a reference to all visible cards on the board (src/App.vue:420-422) to enable keyboard navigation and range selection. When cards are selected, they're tracked both as an array and as a Set of keys for efficient lookup.

Sources: src/App.vue:60, src/App.vue:420-422, src/App.via:511-522


Application Message System ​

The application displays temporary messages to users through AppMessageBanner. Messages auto-dismiss after 5 seconds.

Message Flow:

Messages are used for:

  • Operation confirmations ("Created new board at...")
  • Error notifications ("Cannot rename Archive column")
  • Status updates ("Removed X missing known boards")

Sources: src/App.vue:61, src/App.vue:873-910


View Preferences ​

The viewPreferences state (src/App.vue:40) stores UI preferences that are persisted to the workspace config:

Preference Structure:

PreferenceTypePurpose
card-reorderbooleanEnable/disable drag-and-drop card reordering

The isCardReorderEnabled() utility checks if card reordering is enabled (src/App.vue:67). This preference gates features like:

  • Drag-and-drop card movement
  • Keyboard card movement with Space+Arrows
  • Card move mode activation

Sources: src/App.vue:40, src/App.vue:67, src/App.vue:81-85


Board Lineage and Navigation ​

The application maintains a breadcrumb-style navigation path through nested boards:

Lineage Computation:

The boardLineage computed property (src/App.vue:33) builds an array representing the path from the workspace root to the currently selected board. This powers:

  • Breadcrumb navigation in AppHeader
  • Parent board resolution for board deletion
  • Hierarchical board traversal

Sources: src/App.vue:33, src/App.vue:773-776


Column and Section Management ​

Boards organize cards into columns, which can optionally contain sections. The frontend handles column operations through useBoardActions:

Column Operations:

OperationFunctionTracked in History
Add columnaddColumn()Yes
Rename columnrenameColumn()Yes
Delete columndeleteColumn()Yes
Reorder columnsreorderColumns()Yes

Special Columns:

Sources: src/App.vue:264-294, src/App.vue:437-475, src/App.vue:812-863


Card Move Operations ​

Card movement is one of the most complex operations, supporting both drag-and-drop and keyboard-based movement:

Card Move Data Structure:

typescript
interface CardMovePayload {
    cardSlug: string;
    sourceBoardSlug: string;
    targetColumnName: string;
    targetColumnSlug: string;
    targetSectionName: string | null;
    targetSectionSlug: string | null;
    targetIndex: number;
}

Keyboard Card Movement:

The keyboard movement system (src/App.vue:1323-1367) calculates target positions based on arrow key direction:

  • Up/Down: Moves card within the same column, respecting section boundaries
  • Left/Right: Moves card to adjacent column at same vertical position

The getKeyboardCardMoveTarget() function (src/App.vue:1397-1501) computes the target location by:

  1. Flattening column cards into a single array with section metadata
  2. Computing target index based on direction and current position
  3. Adjusting for same-section moves (decrement index if moving within section)
  4. Handling empty columns and edge cases

Sources: src/App.vue:531-610, src/App.vue:1323-1513


Board Deletion ​

Board deletion is a complex operation that handles cascading deletion of sub-boards:

Deletion Flow:

The countDescendantBoards() function (src/App.vue:1229-1258) performs a depth-first traversal to count all descendant boards, which is used to display an accurate confirmation message.

Sources: src/App.vue:758-810, src/App.vue:1229-1258


Summary ​

The KanStack frontend is built on Vue 3's Composition API with a clear separation of concerns:

  • App.vue orchestrates all composables and handles global interactions
  • Composables manage domain-specific state and operations
  • Components are pure presentation with no business logic
  • State flows unidirectionally from composables to components via props
  • User actions flow upward through events to App.vue
  • All mutations are tracked for undo/redo functionality
  • IPC communication is handled through Tauri's invoke API

This architecture makes the frontend maintainable, testable, and easy to extend with new features.

Sources: src/App.vue:1-1537, src/main.ts:1-6, package.json:1-29