DevelopersArchitecture

Architecture

Understanding Lokus’s architecture helps you contribute effectively, build powerful plugins, and extend the platform. This guide covers the system design, data flow, and key architectural decisions.

Overview

Lokus is a hybrid desktop application combining modern web technologies with native performance through Tauri. The architecture is designed for local-first operation, extensibility, and blazing-fast performance.

Design Principles

  1. Local-First: All data stored locally, offline-capable by default
  2. Performance: Rust backend for intensive operations, optimized React frontend
  3. Extensibility: Plugin system with sandboxed execution
  4. Security: Defense in depth with multiple security layers
  5. Developer Experience: Clear APIs, comprehensive docs, easy debugging

System Architecture

┌─────────────────────────────────────────────────────────────┐
│                     Lokus Application                        │
│                                                              │
│  ┌────────────────────────────────────────────────────┐    │
│  │             Frontend Layer (React 19)               │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  UI Layer                                    │  │    │
│  │  │  - Workspace, Canvas, Graph, Preferences     │  │    │
│  │  │  - Bases (Database Views)                    │  │    │
│  │  │  - Settings, Command Palette                 │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Editor System (TipTap 3.4)                  │  │    │
│  │  │  - ProseMirror Core                          │  │    │
│  │  │  - Custom Extensions (WikiLink, Math, etc.)  │  │    │
│  │  │  - Input Rules & Commands                    │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Core Systems                                │  │    │
│  │  │  - Plugin Manager, Theme Engine              │  │    │
│  │  │  - Config, Auth, Clipboard                   │  │    │
│  │  │  - Search UI, Graph Rendering                │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  State Management                            │  │    │
│  │  │  - React Context (Theme, Workspace, Editor)  │  │    │
│  │  │  - Local State (Hooks, Component State)      │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  └────────────────────────────────────────────────────┘    │
│                           ⬍                                 │
│                  Tauri IPC Bridge (JSON-RPC)                │
│                           ⬍                                 │
│  ┌────────────────────────────────────────────────────┐    │
│  │        Backend Layer (Rust/Tauri 2.0)              │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Core Services                               │  │    │
│  │  │  - File System (I/O, Watching)               │  │    │
│  │  │  - Search Engine (Regex, Indexing)           │  │    │
│  │  │  - Task Management                           │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Security & Auth                             │  │    │
│  │  │  - OAuth2/PKCE (Gmail)                       │  │    │
│  │  │  - Token Management (Keyring)                │  │    │
│  │  │  - Encryption (AES-GCM)                      │  │    │
│  │  │  - Secure Storage                            │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Plugin Backend                              │  │    │
│  │  │  - Plugin Validation & Verification          │  │    │
│  │  │  - Permission Enforcement                    │  │    │
│  │  │  - Resource Isolation & Limits               │  │    │
│  │  │  - Sandbox Management                        │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  │  ┌──────────────────────────────────────────────┐  │    │
│  │  │  Integrations                                │  │    │
│  │  │  - MCP Server (stdio/WebSocket)              │  │    │
│  │  │  - Gmail Integration                         │  │    │
│  │  │  - PDF/OCR Processing                        │  │    │
│  │  │  - Multimedia Library                        │  │    │
│  │  └──────────────────────────────────────────────┘  │    │
│  └────────────────────────────────────────────────────┘    │
│                           ⬍                                 │
│                    Operating System                         │
│              (File System, Network, Keychain)               │
└─────────────────────────────────────────────────────────────┘

Technology Stack

Frontend Technologies

React 19

  • Latest React with concurrent features
  • Hooks-based architecture
  • Context API for global state
  • Suspense for data fetching
  • React.memo for optimization

TipTap 3.4.x (Editor)

  • Built on ProseMirror
  • Extensible node/mark system
  • Real-time collaboration ready
  • Custom extensions for Lokus features

Vite 7.0 (Build Tool)

  • Lightning-fast HMR (Hot Module Replacement)
  • ESM-first architecture
  • Optimized production builds
  • Plugin ecosystem

Tailwind CSS 3.4

  • Utility-first CSS framework
  • Custom design tokens
  • Dark mode support
  • JIT compiler

Key Libraries

{
  "visualization": ["three.js", "sigma.js", "react-force-graph"],
  "canvas": ["tldraw 3.15"],
  "math": ["katex 0.16"],
  "search": ["minisearch 7.2"],
  "state": ["zustand (planned)"],
  "testing": ["vitest 3.2", "playwright 1.55"]
}

Backend Technologies

Tauri 2.0

  • Cross-platform desktop framework
  • Rust core + web frontend
  • ~10MB bundle vs ~100MB Electron
  • Better security model
  • Direct OS API access

Rust (Stable Edition 2021)

  • Memory safety without garbage collection
  • Zero-cost abstractions
  • Fearless concurrency
  • Rich type system

Key Crates

[core]
tokio = "1.0"          # Async runtime
serde = "1.0"          # Serialization
reqwest = "0.12"       # HTTP client
walkdir = "2.0"        # File traversal
regex = "1.0"          # Pattern matching
 
[security]
aes-gcm = "0.10"       # Encryption
argon2 = "0.5"         # Key derivation
oauth2 = "4.4"         # OAuth flows
keyring = "3.6"        # Secure storage
 
[integrations]
lettre = "0.11"        # Email (Gmail)
pdf-extract = "0.7"    # PDF processing
image = "0.24"         # Image processing

Core Components

1. Editor System

Location: src/editor/

The editor is built on TipTap (ProseMirror) with custom extensions for Lokus-specific features.

Architecture

TipTap Editor Instance
├── Core Extensions
│   ├── Starter Kit (Bold, Italic, Heading, etc.)
│   ├── Code Block (Lowlight syntax highlighting)
│   ├── Table (Resizable columns)
│   ├── Image (Lazy loading)
│   └── Task List (Checkbox support)
├── Custom Extensions
│   ├── WikiLink.js - Bidirectional linking with autocomplete
│   ├── Math.js - KaTeX inline and block equations
│   ├── SmartTask.js - Enhanced task management
│   ├── Template.js - Template variable expansion
│   └── SlashCommand.js - Command palette integration
├── Input Rules
│   ├── Markdown shortcuts (**, __, ~~, etc.)
│   ├── Smart quotes and dashes
│   └── Auto-linking
└── Commands & Shortcuts
    ├── Editor commands (format, insert, etc.)
    ├── Keyboard shortcuts
    └── Context menu integration

Extension Types

Nodes (Block-level content)

  • Paragraphs, headings, code blocks
  • Tables, images, horizontal rules
  • Custom: WikiLink blocks, Math blocks

Marks (Inline formatting)

  • Bold, italic, underline, strikethrough
  • Links, code, highlights
  • Custom: Superscript, subscript

Extensions (General functionality)

  • History (undo/redo)
  • Placeholder text
  • Drop handling
  • Paste handling

Key Files

src/editor/
├── components/
│   ├── Editor.jsx           # Main editor component
│   ├── Toolbar.jsx          # Formatting toolbar
│   ├── BubbleMenu.jsx       # Context menu
│   └── SlashMenu.jsx        # Command palette
├── extensions/
│   ├── wiki-link.jsx        # Wiki linking
│   ├── math.jsx             # Math equations
│   ├── smart-task.jsx       # Task management
│   └── slash-command.jsx    # Slash commands
└── lib/
    ├── markdown.js          # Markdown conversion
    ├── paste-handler.js     # Smart paste
    └── suggestions.js       # Autocomplete

2. Plugin System

Location: src/plugins/, src-tauri/src/plugins.rs

VS Code-inspired plugin architecture with sandboxed JavaScript execution.

Architecture

Plugin Manager (Frontend)
├── Plugin Loader
│   ├── Manifest Validation
│   ├── Dependency Resolution
│   └── Sandboxed Execution (isolated-vm)
├── Plugin API (LokusPluginAPI)
│   ├── Editor API - Read/write editor content
│   ├── UI API - Create panels, dialogs, notifications
│   ├── Filesystem API - File operations (sandboxed)
│   ├── Commands API - Register commands
│   ├── Network API - HTTP requests (CORS-aware)
│   ├── Clipboard API - Copy/paste operations
│   ├── Notifications API - Show notifications
│   └── Data API - Access workspace data
├── Plugin Registry
│   ├── Plugin Discovery & Search
│   ├── Version Management
│   ├── Ratings & Reviews
│   └── Download & Install
└── Plugin Backend (Rust)
    ├── Manifest Parsing & Validation
    ├── Permission System
    ├── Resource Limits (CPU, memory)
    ├── File Access Control
    └── Network Policies

Security Model

Sandboxing

  • JavaScript execution in isolated VM
  • No direct access to Node.js APIs
  • No access to file system without permission
  • Limited network access

Permission System

{
  "permissions": [
    "editor:read",        // Read editor content
    "editor:write",       // Modify editor content
    "fs:read",           // Read files (workspace only)
    "fs:write",          // Write files (workspace only)
    "network:request",   // Make HTTP requests
    "ui:create",         // Create UI elements
    "commands:register", // Register commands
    "clipboard:read",    // Read clipboard
    "clipboard:write",   // Write clipboard
    "notifications:show" // Show notifications
  ]
}

Resource Isolation

  • CPU time limits per plugin
  • Memory limits (heap size)
  • Concurrent operation limits
  • Request rate limiting

Plugin Lifecycle

Plugin Installation

Manifest Validation

Permission Request → User Approval

Dependency Installation

Plugin Activation

Plugin Running ←→ Hot Reload (Dev Mode)

Plugin Deactivation

Cleanup

Key Files

src/plugins/
├── PluginManager.js         # Core orchestration
├── api/
│   └── LokusPluginAPI.js    # Public API surface
├── sandbox/
│   └── isolated-vm.js       # Sandbox implementation
└── registry/
    └── PluginRegistry.js    # Plugin discovery

src-tauri/src/
└── plugins.rs               # Backend validation

3. MCP Server

Location: src/mcp-server/, src-tauri/src/mcp.rs

Model Context Protocol server for AI integration with 68+ tools.

Architecture

MCP Server
├── Transport Layer
│   ├── stdio (Primary) - Standard I/O communication
│   ├── WebSocket (Legacy) - WebSocket connections
│   └── HTTP REST (Archived) - RESTful endpoints
├── Tools Registry (68+ tools)
│   ├── Note Tools (11)
│   │   ├── create_note, read_note, update_note
│   │   ├── delete_note, list_notes, search_notes
│   │   └── get_note_metadata, add_tags, etc.
│   ├── Workspace Tools (12)
│   │   ├── list_files, get_workspace_stats
│   │   ├── bulk_operations, folder_management
│   │   └── workspace_config, backup, restore
│   ├── Search Tools (16)
│   │   ├── full_text_search, regex_search
│   │   ├── semantic_search, tag_search
│   │   └── advanced_filters, search_in_path
│   ├── File Tools (6)
│   │   ├── move_file, rename_file, copy_file
│   │   ├── delete_file, get_file_info
│   │   └── batch_file_operations
│   ├── Editor Tools (10)
│   │   ├── format_markdown, validate_syntax
│   │   ├── insert_template, apply_refactoring
│   │   └── extract_toc, generate_summary
│   └── AI Tools (10)
│       ├── analyze_content, suggest_tags
│       ├── generate_title, find_similar
│       └── summarize, extract_entities
├── Resources Registry
│   ├── Note Resources
│   ├── Workspace Resources
│   ├── Config Resources
│   └── Theme Resources
└── Prompts Registry
    └── Template Prompts

Communication Protocol

JSON-RPC 2.0 over stdio/WebSocket/HTTP

// Request
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_note",
    "arguments": {
      "title": "My Note",
      "content": "Note content"
    }
  }
}
 
// Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "path": "/notes/my-note.md",
    "created": true
  }
}

Key Files

src/mcp-server/
├── stdio-server.js          # Main server (stdio transport)
├── tools/
│   ├── note-tools.js        # Note operations
│   ├── workspace-tools.js   # Workspace operations
│   ├── search-tools.js      # Search operations
│   └── ai-tools.js          # AI-powered tools
└── resources/
    └── note-resources.js    # Resource providers

src-tauri/src/
├── mcp.rs                   # Process management
├── mcp_setup.rs             # Server initialization
└── mcp_embedded.rs          # Bundled server

4. File System

Location: src-tauri/src/main.rs, src-tauri/src/handlers/

All file operations go through the Rust backend for security and performance.

Architecture

Frontend Request

Tauri IPC (invoke)

Path Validation & Sanitization

Workspace Boundary Check

Permission Verification

File Operation (Async with Tokio)

Error Handling

Response to Frontend

Security Measures

Path Validation

fn validate_path(path: &str, workspace: &str) -> Result<PathBuf, Error> {
    let absolute = fs::canonicalize(path)?;
    let workspace = fs::canonicalize(workspace)?;
 
    // Prevent directory traversal
    if !absolute.starts_with(&workspace) {
        return Err(Error::PathTraversal);
    }
 
    Ok(absolute)
}

File Type Validation

  • Markdown files (.md)
  • Images (.png, .jpg, .gif, .svg, .webp)
  • PDFs (.pdf)
  • JSON configuration (.json)
  • Block potentially dangerous files (.exe, .dll, .sh)

Size Limits

  • Single file read: 100MB
  • Single file write: 100MB
  • Batch operations: 1000 files
  • Image uploads: 25MB

Key Operations

// Core file operations
read_file_content(path: String) -> Result<String>
write_file_content(path: String, content: String) -> Result<()>
read_workspace_files(workspace: String) -> Result<Vec<FileInfo>>
delete_file(path: String) -> Result<()>
move_file(from: String, to: String) -> Result<()>
copy_file(from: String, to: String) -> Result<()>
 
// OS integration
reveal_in_finder(path: String) -> Result<()>
open_external(path: String) -> Result<()>
 
// Watching
watch_workspace(path: String) -> Result<()>
unwatch_workspace() -> Result<()>

5. Search Engine

Location: src-tauri/src/search.rs

High-performance full-text search powered by Rust.

Architecture

Search Query (Frontend)

Query Parsing (Rust)

Regex Compilation (cached)

Parallel File Traversal (WalkDir + Rayon)

Pattern Matching (per file)

Context Extraction (lines before/after)

Result Ranking & Scoring

XSS-Safe Highlighting

Streaming Results to Frontend

Features

Query Types

  • Full-text search (case-sensitive/insensitive)
  • Regex patterns
  • Multiple search terms (AND/OR)
  • Exclude patterns (NOT)
  • File path filters
  • Tag filters
  • Date range filters

Optimizations

// Parallel search across files
use rayon::prelude::*;
 
files.par_iter()
    .filter_map(|file| search_file(file, &query))
    .collect()
 
// Regex caching
lazy_static! {
    static ref REGEX_CACHE: Mutex<LruCache<String, Regex>> =
        Mutex::new(LruCache::new(100));
}
 
// Early termination
if results.len() >= max_results {
    break;
}

Result Format

{
  "path": "/notes/my-note.md",
  "matches": [
    {
      "line": 42,
      "text": "This is the matched line",
      "highlighted": "This is the <mark>matched</mark> line",
      "context": {
        "before": ["line 41"],
        "after": ["line 43"]
      }
    }
  ],
  "score": 0.95
}

Key Files

src-tauri/src/
├── search.rs               # Core search logic
└── search.test.rs          # Search tests

6. Theme System

Location: src/core/theme/, src-tauri/src/theme.rs

Dynamic theming with CSS custom properties and live preview.

Architecture

Theme Definition (JSON)

Schema Validation (Zod)

CSS Variable Generation

Style Injection (document.documentElement)

Editor Theme Application

Syntax Highlighting Update

Graph Colors Update

Live Preview

Theme Structure

interface Theme {
  id: string;
  name: string;
  type: 'light' | 'dark';
  author?: string;
  version?: string;
 
  colors: {
    // Core colors
    background: string;
    foreground: string;
    primary: string;
    secondary: string;
    accent: string;
 
    // UI colors (15+ tokens)
    border: string;
    input: string;
    card: string;
    popover: string;
    muted: string;
    // ... more
  };
 
  taskColors: {
    todo: string;
    inProgress: string;
    completed: string;
    cancelled: string;
    blocked: string;
    review: string;
    backlog: string;
  };
 
  syntax: {
    comment: string;
    keyword: string;
    string: string;
    number: string;
    function: string;
    // ... more
  };
 
  graph?: {
    node: string;
    edge: string;
    highlight: string;
    cluster: string[];
  };
}

CSS Variables

:root {
  /* Core colors */
  --background: 0 0% 100%;
  --foreground: 0 0% 3.9%;
  --primary: 0 0% 9%;
  --primary-foreground: 0 0% 98%;
 
  /* Component colors */
  --card: 0 0% 100%;
  --card-foreground: 0 0% 3.9%;
  --border: 0 0% 89.8%;
 
  /* Task colors */
  --task-todo: 217 91% 60%;
  --task-completed: 142 76% 36%;
 
  /* Syntax colors */
  --syntax-comment: 0 0% 50%;
  --syntax-keyword: 262 90% 50%;
}

Key Files

src/core/theme/
├── manager.js              # Theme management
├── themes/                 # Built-in themes
│   ├── light.json
│   ├── dark.json
│   └── nord.json
└── schema.js               # Theme validation

src-tauri/src/
└── theme.rs                # Theme persistence

7. Authentication System

Location: src-tauri/src/auth.rs

OAuth2 implementation with secure token storage.

OAuth Flow

1. User initiates OAuth (Gmail integration)

2. Generate PKCE challenge (SHA-256)

3. Open browser with authorization URL

4. User authenticates with provider

5. Provider redirects to localhost callback

6. Start temporary HTTP server (localhost:3000)

7. Receive authorization code

8. Exchange code for tokens (access + refresh)

9. Store tokens in system keychain (encrypted)

10. Return success to application

Security Features

PKCE (Proof Key for Code Exchange)

// Generate code verifier (random 128 bytes)
let verifier = PkceCodeVerifier::new(generate_random_string(128));
 
// Generate code challenge (SHA-256 hash)
let challenge = PkceCodeChallenge::from_code_verifier_sha256(&verifier);
 
// Include in authorization URL
let auth_url = client
    .authorize_url(|| CsrfToken::new(state.clone()))
    .set_pkce_challenge(challenge)
    .url();

Token Storage

use keyring::Entry;
 
// Store in system keychain
let entry = Entry::new("lokus", "gmail_access_token")?;
entry.set_password(&token)?;
 
// Retrieve from keychain
let token = entry.get_password()?;

Token Encryption

use aes_gcm::{Aes256Gcm, Key, Nonce};
use argon2::Argon2;
 
// Derive key from machine ID
let machine_id = get_machine_id()?;
let key = derive_key(&machine_id)?;
 
// Encrypt token
let cipher = Aes256Gcm::new(&key);
let encrypted = cipher.encrypt(&nonce, token.as_bytes())?;

Token Refresh

// Automatic token refresh before expiry
async fn refresh_token(refresh_token: &str) -> Result<TokenResponse> {
    let client = create_oauth_client();
    let token = client
        .exchange_refresh_token(&RefreshToken::new(refresh_token.to_string()))
        .request_async(async_http_client)
        .await?;
 
    store_tokens(&token).await?;
    Ok(token)
}

Key Files

src-tauri/src/
├── auth.rs                 # OAuth implementation
├── oauth_server.rs         # Callback server
└── secure_storage.rs       # Token storage

Data Flow

User Action Flow

User clicks "Save" button

React Event Handler

Component updates local state

useEditor hook

Tauri invoke("write_file_content", { path, content })

IPC serialization (JSON)

Rust command handler

Path validation & permission check

Async file write (Tokio)

File system

Success/Error response

IPC deserialization

Promise resolution

UI update (success notification)

Plugin Execution Flow

User invokes plugin command

Command Palette

Plugin Manager.executeCommand()

Permission check (can plugin run command?)

Create sandbox environment

Load plugin code into isolated-vm

Execute plugin function

Plugin calls API (e.g., api.editor.getContent())

API boundary check (permission granted?)

Core system (Editor)

Return result to sandbox

Plugin processes result

Plugin completes

Cleanup sandbox

Search Flow

User types in search box

Debounced input (300ms)

Search component state update

Tauri invoke("search_workspace", { query, options })

Rust search handler

Parse query (regex, filters, etc.)

Compile regex (with caching)

Parallel file traversal (WalkDir + Rayon)

For each file:
    ├── Read file content
    ├── Apply regex match
    ├── Extract context lines
    └── Calculate relevance score

Sort results by score

Highlight matches (XSS-safe)

Return results (stream for large result sets)

Frontend receives results

Update UI with results

User clicks result → Open note

State Management

Frontend State

React Context

// Global state contexts
ThemeContext         // Current theme, theme settings
WorkspaceContext     // Current workspace path, files
EditorContext        // Editor instance, current note
FolderScopeContext   // Current folder scope for filtering
PluginContext        // Loaded plugins, plugin state

Component State

// Local component state
useState             // Simple state
useReducer          // Complex state with actions
useRef              // Mutable refs, DOM refs
useMemo             // Computed values
useCallback         // Memoized callbacks

Persistent State

// Frontend persistence
localStorage        // UI preferences, recent files
sessionStorage      // Temporary session data
 
// Backend persistence (via Tauri)
Tauri Store         // App settings (.settings.dat)
File system         // User notes, configurations
Keychain            // Credentials (OAuth tokens)

Backend State

In-Memory State (Rust)

// Singleton state with lazy_static
lazy_static! {
    static ref PLUGIN_REGISTRY: Mutex<PluginRegistry> =
        Mutex::new(PluginRegistry::new());
 
    static ref SEARCH_CACHE: Mutex<LruCache<String, SearchResults>> =
        Mutex::new(LruCache::new(100));
 
    static ref FILE_WATCHER: Mutex<Option<FileWatcher>> =
        Mutex::new(None);
}

Persistent State

~/.lokus/
├── settings.dat           # Tauri Store (binary)
├── config.json            # App configuration
├── themes/                # Custom themes
├── plugins/               # Installed plugins
└── cache/                 # Search index, etc.

System Keychain

macOS: Keychain Access
Windows: Windows Credential Manager
Linux: Secret Service API (gnome-keyring, kwallet)

Performance Architecture

Frontend Optimizations

React Performance

// Code splitting
const Canvas = lazy(() => import('./views/Canvas'));
const Graph = lazy(() => import('./views/Graph'));
 
// Component memoization
export default React.memo(ExpensiveComponent);
 
// Callback memoization
const handleClick = useCallback(() => {
  // Handler logic
}, [dependencies]);
 
// Value memoization
const expensiveValue = useMemo(() => {
  return computeExpensiveValue(data);
}, [data]);

Editor Performance

// Debounced saves
const debouncedSave = useMemo(
  () => debounce((content) => saveFile(content), 1000),
  []
);
 
// Virtual scrolling for long documents
import { useVirtualizer } from '@tanstack/react-virtual';
 
// Lazy loading
const lazyLoadImages = () => {
  const images = document.querySelectorAll('img[data-src]');
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        observer.unobserve(img);
      }
    });
  });
 
  images.forEach(img => observer.observe(img));
};

Build Optimizations

// vite.config.js
export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor': ['react', 'react-dom'],
          'editor': ['@tiptap/react', '@tiptap/starter-kit'],
          'graph': ['three', 'sigma', 'graphology']
        }
      }
    },
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  }
};

Backend Optimizations

Async I/O

use tokio::fs;
use tokio::io::AsyncReadExt;
 
#[tauri::command]
async fn read_file_content(path: String) -> Result<String, Error> {
    let mut file = fs::File::open(path).await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    Ok(contents)
}

Parallel Processing

use rayon::prelude::*;
 
// Parallel file search
let results: Vec<SearchResult> = files
    .par_iter()
    .filter_map(|file| search_file(file, &query))
    .collect();

Caching

use lru::LruCache;
use std::sync::Mutex;
 
lazy_static! {
    static ref REGEX_CACHE: Mutex<LruCache<String, Regex>> =
        Mutex::new(LruCache::new(100));
}
 
fn get_cached_regex(pattern: &str) -> Result<Regex, Error> {
    let mut cache = REGEX_CACHE.lock().unwrap();
 
    if let Some(regex) = cache.get(pattern) {
        return Ok(regex.clone());
    }
 
    let regex = Regex::new(pattern)?;
    cache.put(pattern.to_string(), regex.clone());
    Ok(regex)
}

Memory Optimization

// Stream large files instead of loading into memory
use tokio::io::BufReader;
 
async fn process_large_file(path: &str) -> Result<(), Error> {
    let file = fs::File::open(path).await?;
    let reader = BufReader::new(file);
    let mut lines = reader.lines();
 
    while let Some(line) = lines.next_line().await? {
        process_line(&line)?;
    }
 
    Ok(())
}

Security Architecture

Defense in Depth

Layer 1: Input Validation

fn validate_input(input: &str) -> Result<String, Error> {
    // Length check
    if input.len() > MAX_INPUT_LENGTH {
        return Err(Error::InputTooLong);
    }
 
    // Character whitelist
    if !input.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_') {
        return Err(Error::InvalidCharacters);
    }
 
    // SQL injection prevention (if using SQL)
    // XSS prevention (HTML encoding)
 
    Ok(input.to_string())
}

Layer 2: Path Validation

fn validate_path(path: &str, workspace: &str) -> Result<PathBuf, Error> {
    // Resolve to absolute path
    let absolute = fs::canonicalize(path)?;
    let workspace = fs::canonicalize(workspace)?;
 
    // Prevent directory traversal
    if !absolute.starts_with(&workspace) {
        return Err(Error::PathTraversal);
    }
 
    // Prevent symlink attacks
    if absolute.is_symlink() {
        let target = fs::read_link(&absolute)?;
        if !target.starts_with(&workspace) {
            return Err(Error::SymlinkAttack);
        }
    }
 
    Ok(absolute)
}

Layer 3: Permission System

class PluginPermissionManager {
  checkPermission(pluginId, permission) {
    const plugin = this.registry.get(pluginId);
 
    if (!plugin.manifest.permissions.includes(permission)) {
      throw new PermissionError(
        `Plugin ${pluginId} does not have permission: ${permission}`
      );
    }
 
    return true;
  }
}

Layer 4: Sandboxing

import ivm from 'isolated-vm';
 
class PluginSandbox {
  async execute(code, api) {
    const isolate = new ivm.Isolate({ memoryLimit: 128 }); // 128MB limit
    const context = await isolate.createContext();
 
    // Expose limited API
    await context.global.set('api', new ivm.ExternalCopy(api).copyInto());
 
    // No access to Node.js APIs
    // No access to file system
    // No access to network (except through API)
 
    const script = await isolate.compileScript(code);
    return await script.run(context, { timeout: 5000 }); // 5s timeout
  }
}

Layer 5: Encryption

use aes_gcm::{Aes256Gcm, Key, Nonce};
use aes_gcm::aead::{Aead, NewAead};
 
fn encrypt_data(data: &[u8], key: &[u8]) -> Result<Vec<u8>, Error> {
    let key = Key::from_slice(key);
    let cipher = Aes256Gcm::new(key);
 
    let nonce = Nonce::from_slice(generate_nonce()?);
    let ciphertext = cipher.encrypt(nonce, data)
        .map_err(|e| Error::EncryptionFailed(e))?;
 
    Ok(ciphertext)
}

Layer 6: Secure Storage

use keyring::Entry;
 
fn store_secret(service: &str, username: &str, secret: &str) -> Result<(), Error> {
    let entry = Entry::new(service, username)?;
    entry.set_password(secret)?;
    Ok(())
}

Content Security Policy

<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' 'unsafe-inline' 'unsafe-eval';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https: blob:;
  font-src 'self' data:;
  connect-src 'self' https: wss:;
  media-src 'self' blob:;
  object-src 'none';
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
">

Extension Points

Areas designed for customization and extension:

1. Editor Extensions

Create custom TipTap nodes, marks, or extensions:

import { Node } from '@tiptap/core';
 
const CustomNode = Node.create({
  name: 'customNode',
 
  addOptions() {
    return {
      // Options
    };
  },
 
  parseHTML() {
    return [{ tag: 'custom-node' }];
  },
 
  renderHTML({ HTMLAttributes }) {
    return ['custom-node', HTMLAttributes, 0];
  },
 
  addCommands() {
    return {
      insertCustomNode: () => ({ commands }) => {
        return commands.insertContent({
          type: this.name,
          attrs: {}
        });
      }
    };
  }
});

2. Plugins

Full plugin API with sandboxed execution:

class MyPlugin {
  async activate(context) {
    // Register commands
    context.subscriptions.push(
      context.api.commands.register({
        id: 'myPlugin.doSomething',
        handler: () => this.doSomething()
      })
    );
 
    // Create UI panels
    context.api.ui.registerPanel({
      id: 'myPanel',
      title: 'My Panel',
      icon: 'star',
      render: () => this.renderPanel()
    });
  }
 
  async deactivate() {
    // Cleanup
  }
}

3. Themes

Custom color schemes:

{
  "id": "my-theme",
  "name": "My Custom Theme",
  "type": "dark",
  "colors": {
    "background": "#1e1e1e",
    "foreground": "#d4d4d4",
    "primary": "#0078d4"
  },
  "syntax": {
    "comment": "#6a9955",
    "keyword": "#569cd6"
  }
}

4. Templates

Reusable note structures with variables:

---
name: Meeting Notes
category: Work
---
# Meeting: {{title}}
 
Date: {{date:YYYY-MM-DD}}
Attendees: {{cursor}}
 
## Agenda
 
## Notes
 
## Action Items
- [ ]

5. MCP Tools

Custom AI tools:

{
  name: "analyze_sentiment",
  description: "Analyze sentiment of note content",
  inputSchema: {
    type: "object",
    properties: {
      notePath: { type: "string" }
    },
    required: ["notePath"]
  },
  handler: async (params) => {
    const content = await readNote(params.notePath);
    const sentiment = analyzeSentiment(content);
    return { sentiment };
  }
}

6. Data Providers

External data integration:

class JiraDataProvider {
  async fetchIssues(filter) {
    const issues = await this.api.get('/issues', { params: filter });
    return issues.map(issue => ({
      id: issue.key,
      title: issue.fields.summary,
      status: issue.fields.status.name
    }));
  }
}

Build System

Development Build

npm run tauri dev

1. Start Vite dev server (port 1420)
   - Hot Module Replacement (HMR)
   - Source maps enabled
   - React Fast Refresh

2. Cargo build (debug mode)
   - Incremental compilation
   - Fast build times (~10s after initial)

3. Launch Tauri application
   - WebView loads localhost:1420
   - Rust backend connects
   - DevTools enabled

Production Build

npm run build:platform

1. Vite production build
   - Code splitting
   - Tree shaking
   - Minification (Terser)
   - Asset optimization
   - Source maps (optional)

2. Cargo build --release
   - Full optimizations (opt-level=3)
   - LTO (Link Time Optimization)
   - Strip debug symbols
   - ~5-10 min build time

3. Code signing (if configured)
   - macOS: codesign + notarization
   - Windows: Authenticode signing

4. Package creation
   - macOS: DMG, APP bundle
   - Windows: MSI, NSIS installer, portable ZIP
   - Linux: AppImage, DEB, RPM

5. Artifact upload
   - GitHub Releases
   - Update server (if configured)

Build Configuration

Vite (vite.config.js)

export default {
  build: {
    target: 'esnext',
    minify: 'terser',
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          editor: ['@tiptap/react', '@tiptap/starter-kit'],
          graph: ['three', 'sigma', 'graphology']
        }
      }
    }
  },
  server: {
    port: 1420,
    strictPort: true
  }
};

Cargo (Cargo.toml)

[profile.release]
opt-level = 3
lto = true
codegen-units = 1
strip = true
panic = "abort"

Tauri (tauri.conf.json)

{
  "build": {
    "beforeDevCommand": "npm run dev",
    "beforeBuildCommand": "npm run build",
    "devPath": "http://localhost:1420",
    "distDir": "../dist"
  },
  "bundle": {
    "identifier": "com.lokus.app",
    "icon": ["icons/icon.png"],
    "targets": ["dmg", "msi", "appimage"],
    "macOS": {
      "minimumSystemVersion": "10.15"
    },
    "windows": {
      "certificateThumbprint": null,
      "digestAlgorithm": "sha256"
    }
  }
}

Testing Strategy

Unit Tests (Vitest)

// Component tests
import { render, screen } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
 
describe('Editor', () => {
  it('renders editor', () => {
    render(<Editor />);
    expect(screen.getByRole('textbox')).toBeInTheDocument();
  });
});
 
// Utility tests
describe('markdown', () => {
  it('converts markdown to HTML', () => {
    const html = markdownToHtml('# Heading');
    expect(html).toBe('<h1>Heading</h1>');
  });
});

Integration Tests

// API integration tests
describe('File API', () => {
  it('reads and writes files', async () => {
    await invoke('write_file_content', {
      path: '/test.md',
      content: 'Test'
    });
 
    const content = await invoke('read_file_content', {
      path: '/test.md'
    });
 
    expect(content).toBe('Test');
  });
});

E2E Tests (Playwright)

import { test, expect } from '@playwright/test';
 
test('create and edit note', async ({ page }) => {
  await page.goto('/');
 
  // Create note
  await page.click('[data-testid="new-note"]');
  await page.fill('.editor', '# My Note\n\nContent');
 
  // Save
  await page.keyboard.press('Mod+S');
 
  // Verify saved
  await expect(page.locator('.status')).toHaveText('Saved');
});

Next Steps

Now that you understand the architecture:

  1. Explore specific subsystems:

  2. Start contributing:

  3. Build extensions:

Resources