Rust Note Logic Modules
Relevant source files
The following files were used as context for generating this wiki page:
The Rust Note Logic Modules constitute the core backend functionality of the Augenblick application. These modules handle the lifecycle, persistence, and metadata extraction of notes, interfacing between the Tauri frontend and the underlying SQLite database and filesystem. The architecture is modularized to separate concerns such as content derivation, metadata management, and state transitions (e.g., trashing or pinning notes).
The system ensures data integrity by managing two types of note storage: Drafts, which are managed within the application's internal data directory, and Saved notes, which are linked to external files on the user's system. It also implements specific logic for macOS security-scoped bookmarks to maintain file access across sessions.
Architecture Overview
The backend logic is organized into several sub-modules under src-tauri/src/notes/, coordinated by a central entry point.
Module Structure
| Module | Responsibility |
|---|---|
notes.rs | Public API and dispatcher for all note-related operations. |
write.rs | Handling creation, retrieval, and persistence (save/save_as) of notes. |
derive.rs | Logic for extracting titles and previews from raw Markdown content. |
meta.rs | Data mapping between SQLite rows and internal Rust structs. |
import.rs | Logic for importing external Markdown files into the application. |
trash.rs | Managing the trashing, restoration, and permanent deletion of notes. |
ordering.rs | Handling note pinning and manual reordering logic. |
Sources: src-tauri/src/notes.rs:1-12, src-tauri/src/notes/write.rs:1-12
Metadata and Data Modeling
The system uses a structured NoteMeta object to track the state of every note. Metadata is stored in a SQLite table named notes.
Note Data Fields
| Field | Type | Description |
|---|---|---|
id | TEXT | Unique UUID v4 identifier. |
title | TEXT | Derived title (max 80 chars). |
preview | TEXT | Derived content preview (max 140 chars). |
file_path | TEXT | Path to the .md file on disk. |
storage | TEXT | Either "draft" or "saved". |
is_pinned | INTEGER | Boolean flag for pinned status. |
is_trashed | INTEGER | Boolean flag for trashed status. |
sort_order | INTEGER | Numerical value for list positioning. |
created_at | INTEGER | Timestamp of creation (ms). |
last_interaction | INTEGER | Timestamp of last activity (ms). |
Sources: src-tauri/src/notes/meta.rs:5-15, src-tauri/src/notes/write.rs:15-30
Note Storage Flow
This diagram illustrates how the system differentiates between Draft and Saved notes during operations.
The system distinguishes storage types to apply appropriate file access logic. Drafts use direct standard library filesystem calls, while Saved notes utilize a with_scoped_file wrapper for security-scoped access.
Sources: src-tauri/src/notes/write.rs:60-80
Content Derivation Logic
The derive module is responsible for generating human-readable titles and previews from Markdown strings. It performs several cleaning steps to ensure the UI remains clean.
- Sanitization: Strips leading Markdown characters like
#,-,>, and*. - Decoding: Converts HTML entities (e.g.,
to). - Escaping: Removes Markdown escape backslashes.
- Truncation: Limits titles to 80 characters and previews to 140 characters.
pub(super) fn derive_title_preview(content: &str) -> (String, String) {
let lines: Vec<&str> = content
.lines()
.map(|l| l.trim())
.filter(|l| !l.is_empty())
.collect();
let title_line = lines.iter().find(|l| !clean(l).is_empty()).copied().unwrap_or("");
// ... logic to derive title and preview from lines
}
Sources: src-tauri/src/notes/derive.rs:1-25
Note Lifecycle Operations
Creation and Import
New notes are created as drafts within the application's drafts directory. Importing an external file checks for existing records based on the file path; if the note is already known, it updates the metadata and restores it if it was trashed.
Trashing and Restoration
Trashing a note updates its is_trashed flag and moves draft files to a specific trash directory. Restoration reverses this process, moving files back to the drafts directory and resetting flags.
Ordering and Pinning
The ordering module manages the manual and automatic positioning of notes in the UI.
- Pinning: Users can pin up to 5 notes. Pinning a note sets
is_pinned = 1and calculates a newsort_order. - Reordering: When a user drags a note in the UI, the frontend sends an array of IDs. The backend performs a bulk update within a transaction to assign new
sort_ordervalues based on the array index.
pub fn reorder(conn: &mut Connection, ids: &[String]) -> Result<(), String> {
let tx = conn.transaction().map_err(|e| e.to_string())?;
for (idx, id) in ids.iter().enumerate() {
tx.execute(
"UPDATE notes SET sort_order = ?1 WHERE id = ?2 AND is_trashed = 0",
params![idx as i64, id],
).map_err(|e| e.to_string())?;
}
tx.commit().map_err(|e| e.to_string())
}
Sources: src-tauri/src/notes/ordering.rs:40-60, src-tauri/src/notes/meta.rs:30-40
Conclusion
The Rust Note Logic Modules provide a robust foundation for note management by strictly separating the visual derivation of content from the physical storage and state tracking of records. By handling complex tasks such as scoped file access on macOS and transactional reordering, these modules ensure that the user's data remains consistent regardless of whether notes are temporary drafts or permanent external files.