diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html index e94560b68..0fc11a28d 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/AI.html @@ -36,7 +36,7 @@ class="image image_resized" style="width:74.04%;">
To see what embedding models Ollama has available, you can check out
this searchon their website, and then pull whichever one
- you want to try out. As of 4/15/25, my personal favorite is mxbai-embed-large.
mxbai-embed-large.
First, we'll need to select the Ollama provider from the tabs of providers,
then we will enter in the Base URL for our Ollama. Since our Ollama is
running on our local machine, our Base URL is http://localhost:11434.
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html
index 8f28f72f4..d46a3e51c 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Attributes.html
@@ -8,7 +8,7 @@
Labels can be used for a variety of purposes, such as storing metadata or configuring - the behaviour of notes. Labels are also searchable, enhancing note retrieval.
+ the behavior of notes. Labels are also searchable, enhancing note retrieval.For more information, including predefined labels, see Labels.
These attributes play a crucial role in organizing, categorising, and +
These attributes play a crucial role in organizing, categorizing, and enhancing the functionality of notes.
Both the labels and relations for the current note are displayed in the Owned Attributes section diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html index d7068f7eb..196996eed 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Advanced Usage/Custom Request Handler.html @@ -11,7 +11,7 @@ const {secret, title, content} = req.body; if (req.method == 'POST' && secret === 'secret-password') { // notes must be saved somewhere in the tree hierarchy specified by a parent note. // This is defined by a relation from this code note to the "target" parent note - // alternetively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) + // alternatively you can just use constant noteId for simplicity (get that from "Note Info" dialog of the desired parent note) const targetParentNoteId = api.currentNote.getRelationValue('targetNote'); const {note} = api.createTextNote(targetParentNoteId, title, content); @@ -30,7 +30,7 @@ else { be saved
Let's test this by using an HTTP client to send a request:
POST http://my.trilium.org/custom/create-note
+Let's test this by using an HTTP client to send a request:
POST http://your-trilium-server/custom/create-note
Content-Type: application/json
{
@@ -64,12 +64,12 @@ Content-Type: application/json
can always look into its documentation for
details.
Parameters
-REST request paths often contain parameters in the URL, e.g.:
http://my.trilium.org/custom/notes/123
+REST request paths often contain parameters in the URL, e.g.:
http://your-trilium-server/custom/notes/123
The last part is dynamic so the matching of the URL must also be dynamic
- for this reason the matching is done with regular expressions. Following customRequestHandler value
would match it:
notes/([0-9]+)
Additionally, this also defines a matching group with the use of parenthesis
which then makes it easier to extract the value. The matched groups are
available in api.pathParams:
const noteId = api.pathParams[0];
-Often you also need query params (as in e.g. http://my.trilium.org/custom/notes?noteId=123),
+
Often you also need query params (as in e.g. http://your-trilium-server/custom/notes?noteId=123),
you can get those with standard express req.query.noteId.
\ No newline at end of file
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html
index 5a93064e8..0911a8b6c 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Navigation/Search.html
@@ -21,7 +21,7 @@
- Set the text to search for in the Search string field.
- - Apart from searching for words ad-literam, there is also the possibility
+
- Apart from searching for words literally, there is also the possibility
to search for attributes or properties of notes.
- See the examples below for more information.
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html
index 26efd0947..42e484e70 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Notes.html
@@ -31,7 +31,7 @@
and you will see a list of all modified notes including the deleted ones.
Notes available for undeletion have a link to do so. This is kind of "trash
can" functionality known from e.g. Windows.
-Clicking an undelete will recover the note, it's content and attributes
+
Clicking an undelete will recover the note, its content and attributes
- note should be just as before being deleted. This action will also undelete
note's children which have been deleted in the same action.
To be able to undelete a note, it is necessary that deleted note's parent
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html
index 96db62c4b..e23f83d72 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/UI Elements/Ribbon.html
@@ -29,7 +29,7 @@
- Editable changes whether the current note:
- Enters read-only mode automatically if
- the note is too big (default behaviour).
+ the note is too big (default behavior).
- Is always in read-only mode (however it can still be edited temporarily).
- Is always editable, regardless of its size.
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html
index fa40dcfbd..3aaad0a7e 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Collections.html
@@ -1,5 +1,5 @@
-Collections are a unique type of notes that don't have a content, but
- instead display its child notes in various presentation methods.
+Collections are a unique type of note that don't have content, but instead
+ display their child notes in various presentation methods.
Main collections
@@ -94,7 +94,7 @@
in the Ribbon.
Archived notes
By default, archived notes will not be
- shown in collections. This behaviour can be changed by going to Collection Properties in
+ shown in collections. This behavior can be changed by going to Collection Properties in
the Ribbon and
checking Show archived notes.
Archived notes will be generally indicated by being greyed out as opposed
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html
index b213daf6e..5adf8dbe1 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Desktop Installation.html
@@ -27,6 +27,6 @@
any startup scripts that might cause the application to crash.
Synchronization
-For Trilium desktp users who wish to synchronize their data with a server
+
For Trilium desktop users who wish to synchronize their data with a server
instance, refer to the Synchronization guide
for detailed instructions.
\ No newline at end of file
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html
index 0c34a40ae..dfaa68a0d 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Installation & Setup/Server Installation.html
@@ -40,7 +40,7 @@
Disabling / Modifying the Upload Limit
If you're running into the 250MB limit imposed on the server by default,
and you'd like to increase the upload limit, you can set the TRILIUM_NO_UPLOAD_LIMIT environment
- variable to true disable it completely:
export TRILIUM_NO_UPLOAD_LIMIT=true
+ variable to true to disable it completely:export TRILIUM_NO_UPLOAD_LIMIT=true
Or, if you'd simply like to increase the upload limit size to something
beyond 250MB, you can set the MAX_ALLOWED_FILE_SIZE_MB environment
variable to something larger than the integer 250 (e.g. 450 in
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html
index 9c69cade3..1369ccfa6 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html
@@ -1,5 +1,5 @@
-
One core features of Trilium is that it supports multiple types of notes,
- depending on the need.
+One of the core features of Trilium is that it supports multiple types
+ of notes, depending on the need.
Creating a new note with a different type via the note tree
The default note type in Trilium (e.g. when creating a new note) is
Script API provide
extra functionality.
-Scripting
+Architecture Overview
To go further I must explain basic architecture of Trilium - in its essence
it is a classic web application - it has these two main components:
@@ -14,8 +14,8 @@
So we have frontend and backend, each with their own set of responsibilities,
but their common feature is that they both run JavaScript code. Add to
- this the fact, that we're able to create JavaScript [[code notes]] and
- we're onto something.
+ this the fact, that we're able to create JavaScript code notes and we're onto something.
Use cases
- "New Task" launcher button
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html
index 57a0a834b..84a15c29e 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Scripting/Frontend Basics/Custom Widgets/Widget Basics.html
@@ -16,11 +16,11 @@
module.exports = new MyWidget();
To implement this widget:
- - Create a new
JS Frontend note in Trilium and paste in the code
+ - Create a new
JS Frontend note in Trilium and paste in the code
above.
- - Assign the
#widget attribute to
+ - Assign the
#widget attribute to
the note.
- - Restart Trilium or reload the window.
+ - Restart Trilium or reload the window.
To verify that the widget is working, open the developer tools (Cmd + Shift + I)
and run document.querySelector("#my-widget"). If the element
@@ -89,16 +89,15 @@ module.exports = new MyWidget();
module.exports = new MyWidget();
parentWidget() can be given the following values:
- left-pane - This renders the widget on the left side of the
+ left-pane - This renders the widget on the left side of the
screen where the note tree lives.
- center-pane - This renders the widget in the center of the
+ center-pane - This renders the widget in the center of the
layout in the same location that notes and splits appear.
- note-detail-pane - This renders the widget with the
+ note-detail-pane - This renders the widget with the
note in the center pane. This means it can appear multiple times with splits.
- right-pane - This renders the widget to the right of any opened
+ right-pane - This renders the widget to the right of any opened
notes.
-Reload the application
- one last time. When you click the button, a "Hello World!" message should
- appear, confirming that your widget is fully functional.
\ No newline at end of file
+Reload the application one last time.
+ When you click the button, a "Hello World!" message should appear, confirming
+ that your widget is fully functional.
\ No newline at end of file
diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html
index cc53090a9..11b6cdc3c 100644
--- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html
+++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Troubleshooting.html
@@ -1,4 +1,5 @@
-As Trilium is currently in beta, encountering bugs is to be expected.
+While Trilium is actively maintained and stable, encountering bugs is
+ possible.
General Quick Fix
The first step in troubleshooting is often a restart.
If you experience an UI issue, the frontend may have entered an inconsistent
@@ -15,7 +16,7 @@
variable to reset the open tabs to a single specified note ID (e.g., root).
In Linux, you can set it as follows:
TRILIUM_START_NOTE_ID=root ./trilium
Broken Script Prevents Application Startup
-If a custom script causes Triliumto crash, and it is set as a startup
+
If a custom script causes Trilium to crash, and it is set as a startup
script or in an active custom widget, start
Triliumin "safe mode" to prevent any custom scripts from executing:
TRILIUM_SAFE_MODE=true ./trilium
Depending on your Trilium distribution, you may have pre-made scripts
diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md
index 53f35dbd2..1c1d6638b 100644
--- a/docs/ARCHITECTURE.md
+++ b/docs/ARCHITECTURE.md
@@ -1,741 +1,5 @@
-# Trilium Notes - Technical Architecture Documentation
-
-> **Version:** 0.99.3
-> **Last Updated:** November 2025
-> **Maintainer:** TriliumNext Team
-
-## Table of Contents
-
-1. [Introduction](#introduction)
-2. [High-Level Architecture](#high-level-architecture)
-3. [Monorepo Structure](#monorepo-structure)
-4. [Core Architecture Patterns](#core-architecture-patterns)
-5. [Data Layer](#data-layer)
-6. [Caching System](#caching-system)
-7. [Frontend Architecture](#frontend-architecture)
-8. [Backend Architecture](#backend-architecture)
-9. [API Architecture](#api-architecture)
-10. [Build System](#build-system)
-11. [Testing Strategy](#testing-strategy)
-12. [Security Architecture](#security-architecture)
-13. [Related Documentation](#related-documentation)
-
----
-
-## Introduction
-
-Trilium Notes is a hierarchical note-taking application built as a TypeScript monorepo. It supports multiple deployment modes (desktop, server, mobile web) and features advanced capabilities including synchronization, scripting, encryption, and rich content editing.
-
-### Key Characteristics
-
-- **Monorepo Architecture**: Uses pnpm workspaces for dependency management
-- **Multi-Platform**: Desktop (Electron), Server (Node.js/Express), and Mobile Web
-- **TypeScript-First**: Strong typing throughout the codebase
-- **Plugin-Based**: Extensible architecture for note types and UI components
-- **Offline-First**: Full functionality without network connectivity
-- **Synchronization-Ready**: Built-in sync protocol for multi-device usage
-
-### Technology Stack
-
-- **Runtime**: Node.js (backend), Browser/Electron (frontend)
-- **Language**: TypeScript, JavaScript
-- **Database**: SQLite (better-sqlite3)
-- **Build Tools**: Vite, ESBuild, pnpm
-- **UI Framework**: Custom widget-based system
-- **Rich Text**: CKEditor 5 (customized)
-- **Code Editing**: CodeMirror 6
-- **Desktop**: Electron
-- **Server**: Express.js
-
----
-
-## High-Level Architecture
-
-Trilium follows a **client-server architecture** even in desktop mode, where Electron runs both the backend server and frontend client within the same process.
-
-```mermaid
-graph TB
- subgraph Frontend
- Widgets[Widgets
System]
- Froca[Froca
Cache]
- UIServices[UI
Services]
- end
-
- subgraph Backend["Backend Server"]
- Express[Express
Routes]
- Becca[Becca
Cache]
- ScriptEngine[Script
Engine]
- Database[(SQLite
Database)]
- end
-
- Widgets -.-> API[WebSocket / REST API]
- Froca -.-> API
- UIServices -.-> API
- API -.-> Express
- API -.-> Becca
- API -.-> ScriptEngine
- Becca --> Database
- Express --> Database
- ScriptEngine --> Database
-```
-
-### Deployment Modes
-
-1. **Desktop Application**
- - Electron wrapper running both frontend and backend
- - Local SQLite database
- - Full offline functionality
- - Cross-platform (Windows, macOS, Linux)
-
-2. **Server Installation**
- - Node.js server exposing web interface
- - Multi-user capable
- - Can sync with desktop clients
- - Docker deployment supported
-
-3. **Mobile Web**
- - Optimized responsive interface
- - Accessed via browser
- - Requires server installation
-
----
-
-## Monorepo Structure
-
-Trilium uses **pnpm workspaces** to manage its monorepo structure, with apps and packages clearly separated.
-
-```
-trilium/
-├── apps/ # Runnable applications
-│ ├── client/ # Frontend application (shared by server & desktop)
-│ ├── server/ # Node.js server with web interface
-│ ├── desktop/ # Electron desktop application
-│ ├── web-clipper/ # Browser extension for web content capture
-│ ├── db-compare/ # Database comparison tool
-│ ├── dump-db/ # Database export tool
-│ ├── edit-docs/ # Documentation editing tool
-│ ├── build-docs/ # Documentation build tool
-│ └── website/ # Marketing website
-│
-├── packages/ # Shared libraries
-│ ├── commons/ # Shared interfaces and utilities
-│ ├── ckeditor5/ # Custom rich text editor
-│ ├── codemirror/ # Code editor customizations
-│ ├── highlightjs/ # Syntax highlighting
-│ ├── ckeditor5-admonition/ # CKEditor plugin: admonitions
-│ ├── ckeditor5-footnotes/ # CKEditor plugin: footnotes
-│ ├── ckeditor5-keyboard-marker/# CKEditor plugin: keyboard shortcuts
-│ ├── ckeditor5-math/ # CKEditor plugin: math equations
-│ ├── ckeditor5-mermaid/ # CKEditor plugin: diagrams
-│ ├── express-partial-content/ # HTTP partial content middleware
-│ ├── share-theme/ # Shared note theme
-│ ├── splitjs/ # Split pane library
-│ └── turndown-plugin-gfm/ # Markdown conversion
-│
-├── docs/ # Documentation
-├── scripts/ # Build and utility scripts
-└── patches/ # Package patches (via pnpm)
-```
-
-### Package Dependencies
-
-The monorepo uses workspace protocol (`workspace:*`) for internal dependencies:
-
-```
-desktop → client → commons
-server → client → commons
-client → ckeditor5, codemirror, highlightjs
-ckeditor5 → ckeditor5-* plugins
-```
-
----
-
-## Core Architecture Patterns
-
-### Three-Layer Cache System
-
-Trilium implements a sophisticated **three-tier caching system** to optimize performance and enable offline functionality:
-
-#### 1. Becca (Backend Cache)
-
-Located at: `apps/server/src/becca/`
-
-```typescript
-// Becca caches all entities in memory
-class Becca {
- notes: Record
- branches: Record
- attributes: Record
- attachments: Record
- // ... other entity collections
-}
-```
-
-**Responsibilities:**
-- Server-side entity cache
-- Maintains complete note tree in memory
-- Handles entity relationships and integrity
-- Provides fast lookups without database queries
-- Manages entity lifecycle (create, update, delete)
-
-**Key Files:**
-- `becca.ts` - Main cache instance
-- `becca_loader.ts` - Loads entities from database
-- `becca_service.ts` - Cache management operations
-- `entities/` - Entity classes (BNote, BBranch, etc.)
-
-#### 2. Froca (Frontend Cache)
-
-Located at: `apps/client/src/services/froca.ts`
-
-```typescript
-// Froca is a read-only mirror of backend data
-class Froca {
- notes: Record
- branches: Record
- attributes: Record
- // ... other entity collections
-}
-```
-
-**Responsibilities:**
-- Frontend read-only cache
-- Lazy loading of note tree
-- Minimizes API calls
-- Enables fast UI rendering
-- Synchronizes with backend via WebSocket
-
-**Loading Strategy:**
-- Initial load: root notes and immediate children
-- Lazy load: notes loaded when accessed
-- When note is loaded, all parent and child branches load
-- Deleted entities tracked via missing branches
-
-#### 3. Shaca (Share Cache)
-
-Located at: `apps/server/src/share/`
-
-**Responsibilities:**
-- Optimized cache for shared/published notes
-- Handles public note access without authentication
-- Performance-optimized for high-traffic scenarios
-- Separate from main Becca to isolate concerns
-
-### Entity System
-
-Trilium's data model is based on five core entities:
-
-```mermaid
-graph TD
- Note[Note
BNote]
- Branch[Branch
BBranch]
- Attribute[Attribute
BAttribute]
- Revision[Revision
BRevision]
- Attachment[Attachment
BAttachment]
-
- Note -->|linked by| Branch
- Note -.->|metadata| Attribute
- Branch -->|creates| Revision
- Note -->|has| Attachment
-
- style Note fill:#e1f5ff
- style Branch fill:#fff4e1
- style Attribute fill:#ffe1f5
- style Revision fill:#f5ffe1
- style Attachment fill:#ffe1e1
-```
-
-#### Entity Definitions
-
-**1. BNote** (`apps/server/src/becca/entities/bnote.ts`)
-- Represents a note with title, content, and metadata
-- Type can be: text, code, file, image, canvas, mermaid, etc.
-- Contains content via blob reference
-- Can be protected (encrypted)
-- Has creation and modification timestamps
-
-**2. BBranch** (`apps/server/src/becca/entities/bbranch.ts`)
-- Represents parent-child relationship between notes
-- Enables note cloning (multiple parents)
-- Contains positioning information
-- Has optional prefix for customization
-- Tracks expansion state in tree
-
-**3. BAttribute** (`apps/server/src/becca/entities/battribute.ts`)
-- Key-value metadata attached to notes
-- Two types: labels (tags) and relations (links)
-- Can be inheritable to child notes
-- Used for search, organization, and scripting
-- Supports promoted attributes (displayed prominently)
-
-**4. BRevision** (`apps/server/src/becca/entities/brevision.ts`)
-- Stores historical versions of note content
-- Automatic versioning on edits
-- Retains title, type, and content
-- Enables note history browsing and restoration
-
-**5. BAttachment** (`apps/server/src/becca/entities/battachment.ts`)
-- File attachments linked to notes
-- Has owner (note), role, and mime type
-- Content stored in blobs
-- Can be protected (encrypted)
-
-**6. BBlob** (`apps/server/src/becca/entities/bblob.ts`)
-- Binary large object storage
-- Stores actual note content and attachments
-- Referenced by notes, revisions, and attachments
-- Supports encryption for protected content
-
-### Widget-Based UI
-
-The frontend uses a **widget system** for modular, reusable UI components.
-
-Located at: `apps/client/src/widgets/`
-
-```typescript
-// Widget Hierarchy
-BasicWidget
-├── NoteContextAwareWidget (responds to note changes)
-│ ├── RightPanelWidget (displayed in right sidebar)
-│ └── Type-specific widgets
-├── Container widgets (tabs, ribbons, etc.)
-└── Specialized widgets (search, calendar, etc.)
-```
-
-**Base Classes:**
-
-1. **BasicWidget** (`basic_widget.ts`)
- - Base class for all UI components
- - Lifecycle: construction → rendering → events → destruction
- - Handles DOM manipulation
- - Event subscription management
- - Child widget management
-
-2. **NoteContextAwareWidget** (`note_context_aware_widget.ts`)
- - Extends BasicWidget
- - Automatically updates when active note changes
- - Accesses current note context
- - Used for note-dependent UI
-
-3. **RightPanelWidget**
- - Widgets displayed in right sidebar
- - Collapsible sections
- - Context-specific tools and information
-
-**Type-Specific Widgets:**
-
-Located at: `apps/client/src/widgets/type_widgets/`
-
-Each note type has a dedicated widget:
-- `text_type_widget.ts` - CKEditor integration
-- `code_type_widget.ts` - CodeMirror integration
-- `file_type_widget.ts` - File preview and download
-- `image_type_widget.ts` - Image display and editing
-- `canvas_type_widget.ts` - Excalidraw integration
-- `mermaid_type_widget.ts` - Diagram rendering
-- And more...
-
----
-
-## Data Layer
-
-### Database Schema
-
-Trilium uses **SQLite** as its database engine, managed via `better-sqlite3`.
-
-Schema location: `apps/server/src/assets/db/schema.sql`
-
-**Core Tables:**
-
-```sql
--- Notes: Core content storage
-notes (
- noteId, title, isProtected, type, mime,
- blobId, isDeleted, dateCreated, dateModified
-)
-
--- Branches: Tree relationships
-branches (
- branchId, noteId, parentNoteId, notePosition,
- prefix, isExpanded, isDeleted
-)
-
--- Attributes: Metadata
-attributes (
- attributeId, noteId, type, name, value,
- position, isInheritable, isDeleted
-)
-
--- Revisions: Version history
-revisions (
- revisionId, noteId, type, mime, title,
- blobId, utcDateLastEdited
-)
-
--- Attachments: File attachments
-attachments (
- attachmentId, ownerId, role, mime, title,
- blobId, isProtected, isDeleted
-)
-
--- Blobs: Binary content
-blobs (
- blobId, content, dateModified
-)
-
--- Options: Application settings
-options (
- name, value, isSynced
-)
-
--- Entity Changes: Sync tracking
-entity_changes (
- entityName, entityId, hash, changeId,
- isSynced, utcDateChanged
-)
-```
-
-### Data Access Patterns
-
-**Direct SQL:**
-```typescript
-// apps/server/src/services/sql.ts
-sql.getRows("SELECT * FROM notes WHERE type = ?", ['text'])
-sql.execute("UPDATE notes SET title = ? WHERE noteId = ?", [title, noteId])
-```
-
-**Through Becca:**
-```typescript
-// Recommended approach - uses cache
-const note = becca.getNote('noteId')
-note.title = 'New Title'
-note.save()
-```
-
-**Through Froca (Frontend):**
-```typescript
-// Read-only access
-const note = froca.getNote('noteId')
-console.log(note.title)
-```
-
-### Database Migrations
-
-Migration system: `apps/server/src/migrations/`
-
-- Sequential numbered files (e.g., `XXXX_migration_name.sql`)
-- Automatic execution on version upgrade
-- Schema version tracked in options table
-- Both SQL and JavaScript migrations supported
-
----
-
-## Caching System
-
-### Cache Initialization
-
-**Backend (Becca):**
-```typescript
-// On server startup
-await becca_loader.load() // Loads all entities into memory
-becca.loaded = true
-```
-
-**Frontend (Froca):**
-```typescript
-// On app initialization
-await froca.loadInitialTree() // Loads root and visible notes
-// Lazy load on demand
-const note = await froca.getNote(noteId) // Triggers load if not cached
-```
-
-### Cache Invalidation
-
-**Server-Side:**
-- Entities automatically update cache on save
-- WebSocket broadcasts changes to all clients
-- Synchronization updates trigger cache refresh
-
-**Client-Side:**
-- WebSocket listeners update Froca
-- Manual reload via `froca.loadSubTree(noteId)`
-- Full reload on protected session changes
-
-### Cache Consistency
-
-**Entity Change Tracking:**
-```typescript
-// Every entity modification tracked
-entity_changes (
- entityName: 'notes',
- entityId: 'note123',
- hash: 'abc...',
- changeId: 'change456',
- utcDateChanged: '2025-11-02...'
-)
-```
-
-**Sync Protocol:**
-1. Client requests changes since last sync
-2. Server returns entity_changes records
-3. Client applies changes to Froca
-4. Client sends local changes to server
-5. Server updates Becca and database
-
----
-
-## Frontend Architecture
-
-### Application Entry Point
-
-**Desktop:** `apps/client/src/desktop.ts`
-**Web:** `apps/client/src/index.ts`
-
-### Service Layer
-
-Located at: `apps/client/src/services/`
-
-Key services:
-- `froca.ts` - Frontend cache
-- `server.ts` - API communication
-- `ws.ts` - WebSocket connection
-- `tree_service.ts` - Note tree management
-- `note_context.ts` - Active note tracking
-- `protected_session.ts` - Encryption key management
-- `link.ts` - Note linking and navigation
-- `export.ts` - Note export functionality
-
-### UI Components
-
-**Main Layout:**
-
-```mermaid
-graph TD
- subgraph TriliumUI[" "]
- TitleBar[Title Bar]
-
- subgraph MainArea[" "]
- NoteTree[Note Tree]
- NoteDetail[Note Detail
Editor]
- RightPanel[Right Panel
Info, Links]
- end
-
- StatusBar[Status Bar]
- end
-
- TitleBar -.-> MainArea
- MainArea -.-> StatusBar
-
- style TitleBar fill:#e1f5ff
- style NoteTree fill:#fff4e1
- style NoteDetail fill:#f5ffe1
- style RightPanel fill:#ffe1f5
- style StatusBar fill:#e1f5ff
-```
-
-**Component Locations:**
-- `widgets/containers/` - Layout containers
-- `widgets/buttons/` - Toolbar buttons
-- `widgets/dialogs/` - Modal dialogs
-- `widgets/ribbon_widgets/` - Tab widgets
-- `widgets/type_widgets/` - Note type editors
-
-### Event System
-
-**Application Events:**
-```typescript
-// Subscribe to events
-appContext.addBeforeUnloadListener(() => {
- // Cleanup before page unload
-})
-
-// Trigger events
-appContext.trigger('noteTreeLoaded')
-```
-
-**Note Context Events:**
-```typescript
-// NoteContextAwareWidget automatically receives:
-- noteSwitched()
-- noteChanged()
-- refresh()
-```
-
-### State Management
-
-Trilium uses **custom state management** rather than Redux/MobX:
-
-- `note_context.ts` - Active note and context
-- `froca.ts` - Entity cache
-- Component local state
-- URL parameters for shareable state
-
----
-
-## Backend Architecture
-
-### Application Entry Point
-
-Location: `apps/server/src/main.ts`
-
-**Startup Sequence:**
-1. Load configuration
-2. Initialize database
-3. Run migrations
-4. Load Becca cache
-5. Start Express server
-6. Initialize WebSocket
-7. Start scheduled tasks
-
-### Service Layer
-
-Located at: `apps/server/src/services/`
-
-**Core Services:**
-
-- **Notes Management**
- - `notes.ts` - CRUD operations
- - `note_contents.ts` - Content handling
- - `note_types.ts` - Type-specific logic
- - `cloning.ts` - Note cloning/multi-parent
-
-- **Tree Operations**
- - `tree.ts` - Tree structure management
- - `branches.ts` - Branch operations
- - `consistency_checks.ts` - Tree integrity
-
-- **Search**
- - `search/search.ts` - Main search engine
- - `search/expressions/` - Search expression parsing
- - `search/services/` - Search utilities
-
-- **Sync**
- - `sync.ts` - Synchronization protocol
- - `sync_update.ts` - Update handling
- - `sync_mutex.ts` - Concurrency control
-
-- **Scripting**
- - `backend_script_api.ts` - Backend script API
- - `script_context.ts` - Script execution context
-
-- **Import/Export**
- - `import/` - Various import formats
- - `export/` - Export to different formats
- - `zip.ts` - Archive handling
-
-- **Security**
- - `encryption.ts` - Note encryption
- - `protected_session.ts` - Session management
- - `password.ts` - Password handling
-
-### Route Structure
-
-Located at: `apps/server/src/routes/`
-
-```
-routes/
-├── index.ts # Route registration
-├── api/ # REST API endpoints
-│ ├── notes.ts
-│ ├── branches.ts
-│ ├── attributes.ts
-│ ├── search.ts
-│ ├── login.ts
-│ └── ...
-└── custom/ # Special endpoints
- ├── setup.ts
- ├── share.ts
- └── ...
-```
-
-**API Endpoint Pattern:**
-```typescript
-router.get('/api/notes/:noteId', (req, res) => {
- const noteId = req.params.noteId
- const note = becca.getNote(noteId)
- res.json(note.getPojoWithContent())
-})
-```
-
-### Middleware
-
-Key middleware components:
-- `auth.ts` - Authentication
-- `csrf.ts` - CSRF protection
-- `request_context.ts` - Request-scoped data
-- `error_handling.ts` - Error responses
-
----
-
## API Architecture
-### Internal API
-
-**REST Endpoints** (`/api/*`)
-
-Used by the frontend for all operations:
-
-**Note Operations:**
-- `GET /api/notes/:noteId` - Get note
-- `POST /api/notes/:noteId/content` - Update content
-- `PUT /api/notes/:noteId` - Update metadata
-- `DELETE /api/notes/:noteId` - Delete note
-
-**Tree Operations:**
-- `GET /api/tree` - Get note tree
-- `POST /api/branches` - Create branch
-- `PUT /api/branches/:branchId` - Update branch
-- `DELETE /api/branches/:branchId` - Delete branch
-
-**Search:**
-- `GET /api/search?query=...` - Search notes
-- `GET /api/search-note/:noteId` - Execute search note
-
-### ETAPI (External API)
-
-Located at: `apps/server/src/etapi/`
-
-**Purpose:** Third-party integrations and automation
-
-**Authentication:** Token-based (ETAPI tokens)
-
-**OpenAPI Spec:** Auto-generated
-
-**Key Endpoints:**
-- `/etapi/notes` - Note CRUD
-- `/etapi/branches` - Branch management
-- `/etapi/attributes` - Attribute operations
-- `/etapi/attachments` - Attachment handling
-
-**Example:**
-```bash
-curl -H "Authorization: YOUR_TOKEN" \
- https://trilium.example.com/etapi/notes/noteId
-```
-
-### WebSocket API
-
-Located at: `apps/server/src/services/ws.ts`
-
-**Purpose:** Real-time updates and synchronization
-
-**Protocol:** WebSocket (Socket.IO-like custom protocol)
-
-**Message Types:**
-- `sync` - Synchronization request
-- `entity-change` - Entity update notification
-- `refresh-tree` - Tree structure changed
-- `open-note` - Open note in UI
-
-**Client Subscribe:**
-```typescript
-ws.subscribe('entity-change', (data) => {
- froca.processEntityChange(data)
-})
-```
-
----
-
## Build System
### Package Manager: pnpm
@@ -1013,9 +277,3 @@ For historical context on major architectural decisions, see:
- Adoption of pnpm workspaces
- CKEditor 5 upgrade
- Entity change tracking system
-
----
-
-**Document Maintainer:** TriliumNext Team
-**Last Review:** November 2025
-**Next Review:** When major architectural changes occur
diff --git a/docs/Developer Guide/!!!meta.json b/docs/Developer Guide/!!!meta.json
index e75df02a9..a871c66f5 100644
--- a/docs/Developer Guide/!!!meta.json
+++ b/docs/Developer Guide/!!!meta.json
@@ -124,18 +124,687 @@
},
{
"isClone": false,
- "noteId": "zdQzavvHDl1k",
+ "noteId": "MhwWMgxwDTZL",
"notePath": [
"jdjRLhLV3TtI",
- "zdQzavvHDl1k"
+ "MhwWMgxwDTZL"
],
- "title": "Documentation",
+ "title": "Architecture",
"notePosition": 280,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "architecture",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-arch",
+ "isInheritable": false,
+ "position": 30
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "Architecture.md",
+ "attachments": [],
+ "dirFileName": "Architecture",
+ "children": [
+ {
+ "isClone": false,
+ "noteId": "2DJZgzpTJ078",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "2DJZgzpTJ078"
+ ],
+ "title": "Client-server architecture",
+ "notePosition": 10,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [],
+ "format": "markdown",
+ "attachments": [],
+ "dirFileName": "Client-server architecture",
+ "children": [
+ {
+ "isClone": false,
+ "noteId": "dsMq2EIOMOBU",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "2DJZgzpTJ078",
+ "dsMq2EIOMOBU"
+ ],
+ "title": "Frontend",
+ "notePosition": 10,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [],
+ "format": "markdown",
+ "dataFileName": "Frontend.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "tsswRlmHEnYW",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "2DJZgzpTJ078",
+ "tsswRlmHEnYW"
+ ],
+ "title": "Backend",
+ "notePosition": 20,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [],
+ "format": "markdown",
+ "dataFileName": "Backend.md",
+ "attachments": []
+ }
+ ]
+ },
+ {
+ "isClone": false,
+ "noteId": "pRZhrVIGCbMu",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu"
+ ],
+ "title": "Database",
+ "notePosition": 20,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "database",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "Database.md",
+ "attachments": [],
+ "dirFileName": "Database",
+ "children": [
+ {
+ "isClone": false,
+ "noteId": "vNMojjUN76jc",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc"
+ ],
+ "title": "Database structure",
+ "notePosition": 10,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "tables",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 30
+ }
+ ],
+ "format": "markdown",
+ "attachments": [],
+ "dirFileName": "Database structure",
+ "children": [
+ {
+ "isClone": false,
+ "noteId": "e6GnYOXeIWjg",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "e6GnYOXeIWjg"
+ ],
+ "title": "attachments",
+ "notePosition": 20,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "DSkl8C325tEC",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "UvXpeSqfYc6d",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "VIcWnKGs0sMh",
+ "isInheritable": false,
+ "position": 30
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "tM3rIZQzlum4",
+ "isInheritable": false,
+ "position": 40
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "attachments",
+ "isInheritable": false,
+ "position": 50
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "attachments.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "ciL84vNBNi9y",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "ciL84vNBNi9y"
+ ],
+ "title": "attributes",
+ "notePosition": 30,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "DSkl8C325tEC",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "tM3rIZQzlum4",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "attributes",
+ "isInheritable": false,
+ "position": 40
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "attributes.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "VIcWnKGs0sMh",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "VIcWnKGs0sMh"
+ ],
+ "title": "blobs",
+ "notePosition": 40,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "blobs",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "blobs.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "GskLPkgY5n6E",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "GskLPkgY5n6E"
+ ],
+ "title": "branches",
+ "notePosition": 50,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "h8AsuFjSD4fB",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "DSkl8C325tEC",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "tM3rIZQzlum4",
+ "isInheritable": false,
+ "position": 30
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "branches",
+ "isInheritable": false,
+ "position": 40
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "branches.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "ohhExR078MPU",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "ohhExR078MPU"
+ ],
+ "title": "entity_changes",
+ "notePosition": 51,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "entity-changes",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "entity_changes.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "bRqbIg633nCs",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "bRqbIg633nCs"
+ ],
+ "title": "etapi_tokens",
+ "notePosition": 52,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "tM3rIZQzlum4",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "etapi-tokens",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "etapi_tokens.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "DSkl8C325tEC",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "DSkl8C325tEC"
+ ],
+ "title": "notes",
+ "notePosition": 53,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "VIcWnKGs0sMh",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "UvXpeSqfYc6d",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "tM3rIZQzlum4",
+ "isInheritable": false,
+ "position": 30
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "notes",
+ "isInheritable": false,
+ "position": 40
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "notes.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "4oeftEmy77Bt",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "4oeftEmy77Bt"
+ ],
+ "title": "options",
+ "notePosition": 54,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "options",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "options.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "VyFirdgAOoh5",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "VyFirdgAOoh5"
+ ],
+ "title": "recent_notes",
+ "notePosition": 55,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "DSkl8C325tEC",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "recent-notes",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "recent_notes.md",
+ "attachments": []
+ },
+ {
+ "isClone": false,
+ "noteId": "s7ZBiaJVNumK",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "pRZhrVIGCbMu",
+ "vNMojjUN76jc",
+ "s7ZBiaJVNumK"
+ ],
+ "title": "revisions",
+ "notePosition": 56,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "DSkl8C325tEC",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "VIcWnKGs0sMh",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "UvXpeSqfYc6d",
+ "isInheritable": false,
+ "position": 30
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-table",
+ "isInheritable": false,
+ "position": 10
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "revisions",
+ "isInheritable": false,
+ "position": 50
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "revisions.md",
+ "attachments": []
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "isClone": false,
+ "noteId": "Wxn82Em8B7U5",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "MhwWMgxwDTZL",
+ "Wxn82Em8B7U5"
+ ],
+ "title": "API",
+ "notePosition": 30,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [],
+ "format": "markdown",
+ "dataFileName": "API.md",
+ "attachments": []
+ }
+ ]
+ },
+ {
+ "isClone": false,
+ "noteId": "zdQzavvHDl1k",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "zdQzavvHDl1k"
+ ],
+ "title": "Documentation",
+ "notePosition": 290,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "T2W7WCZrYZBU",
+ "isInheritable": false,
+ "position": 10
+ },
{
"type": "label",
"name": "shareAlias",
@@ -149,13 +818,6 @@
"value": "bx bx-book-open",
"isInheritable": false,
"position": 30
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "T2W7WCZrYZBU",
- "isInheritable": false,
- "position": 40
}
],
"format": "markdown",
@@ -200,7 +862,7 @@
"a0mkxxB4Uvbf"
],
"title": "Building",
- "notePosition": 290,
+ "notePosition": 300,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -415,7 +1077,7 @@
"name": "internalLink",
"value": "zdQzavvHDl1k",
"isInheritable": false,
- "position": 20
+ "position": 10
},
{
"type": "label",
@@ -439,7 +1101,7 @@
"qalhAaJoQ7AN"
],
"title": "Dependencies",
- "notePosition": 310,
+ "notePosition": 320,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -682,8 +1344,8 @@
"jdjRLhLV3TtI",
"yeqU0zo0ZQ83"
],
- "title": "Architecture",
- "notePosition": 320,
+ "title": "Concepts",
+ "notePosition": 330,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -692,14 +1354,14 @@
{
"type": "label",
"name": "shareAlias",
- "value": "architecture",
+ "value": "concepts",
"isInheritable": false,
"position": 10
},
{
"type": "label",
"name": "iconClass",
- "value": "bx bx-arch",
+ "value": "bx bx-sitemap",
"isInheritable": false,
"position": 20
},
@@ -713,7 +1375,7 @@
],
"format": "markdown",
"attachments": [],
- "dirFileName": "Architecture",
+ "dirFileName": "Concepts",
"children": [
{
"isClone": false,
@@ -776,6 +1438,33 @@
"dataFileName": "Branch prefixes.md",
"attachments": []
},
+ {
+ "isClone": false,
+ "noteId": "6Yms5izbd0GF",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "yeqU0zo0ZQ83",
+ "6Yms5izbd0GF"
+ ],
+ "title": "Cache",
+ "notePosition": 30,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bx-microchip",
+ "isInheritable": false,
+ "position": 20
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "Cache.md",
+ "attachments": []
+ },
{
"isClone": false,
"noteId": "oqg9OpK8xfcm",
@@ -785,7 +1474,7 @@
"oqg9OpK8xfcm"
],
"title": "CI",
- "notePosition": 30,
+ "notePosition": 40,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -857,511 +1546,6 @@
}
]
},
- {
- "isClone": false,
- "noteId": "vNMojjUN76jc",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc"
- ],
- "title": "Database structure",
- "notePosition": 40,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "label",
- "name": "shareAlias",
- "value": "database",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-data",
- "isInheritable": false,
- "position": 30
- }
- ],
- "format": "markdown",
- "attachments": [],
- "dirFileName": "Database structure",
- "children": [
- {
- "isClone": false,
- "noteId": "e6GnYOXeIWjg",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "e6GnYOXeIWjg"
- ],
- "title": "attachments",
- "notePosition": 20,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "DSkl8C325tEC",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "UvXpeSqfYc6d",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "VIcWnKGs0sMh",
- "isInheritable": false,
- "position": 30
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "tM3rIZQzlum4",
- "isInheritable": false,
- "position": 40
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "attachments",
- "isInheritable": false,
- "position": 50
- }
- ],
- "format": "markdown",
- "dataFileName": "attachments.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "ciL84vNBNi9y",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "ciL84vNBNi9y"
- ],
- "title": "attributes",
- "notePosition": 30,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "DSkl8C325tEC",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "tM3rIZQzlum4",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "attributes",
- "isInheritable": false,
- "position": 40
- }
- ],
- "format": "markdown",
- "dataFileName": "attributes.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "VIcWnKGs0sMh",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "VIcWnKGs0sMh"
- ],
- "title": "blobs",
- "notePosition": 40,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "blobs",
- "isInheritable": false,
- "position": 20
- }
- ],
- "format": "markdown",
- "dataFileName": "blobs.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "GskLPkgY5n6E",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "GskLPkgY5n6E"
- ],
- "title": "branches",
- "notePosition": 50,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "h8AsuFjSD4fB",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "DSkl8C325tEC",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "tM3rIZQzlum4",
- "isInheritable": false,
- "position": 30
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "branches",
- "isInheritable": false,
- "position": 40
- }
- ],
- "format": "markdown",
- "dataFileName": "branches.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "ohhExR078MPU",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "ohhExR078MPU"
- ],
- "title": "entity_changes",
- "notePosition": 51,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "entity-changes",
- "isInheritable": false,
- "position": 20
- }
- ],
- "format": "markdown",
- "dataFileName": "entity_changes.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "bRqbIg633nCs",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "bRqbIg633nCs"
- ],
- "title": "etapi_tokens",
- "notePosition": 52,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "tM3rIZQzlum4",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "etapi-tokens",
- "isInheritable": false,
- "position": 20
- }
- ],
- "format": "markdown",
- "dataFileName": "etapi_tokens.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "DSkl8C325tEC",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "DSkl8C325tEC"
- ],
- "title": "notes",
- "notePosition": 53,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "VIcWnKGs0sMh",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "UvXpeSqfYc6d",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "tM3rIZQzlum4",
- "isInheritable": false,
- "position": 30
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "notes",
- "isInheritable": false,
- "position": 40
- }
- ],
- "format": "markdown",
- "dataFileName": "notes.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "4oeftEmy77Bt",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "4oeftEmy77Bt"
- ],
- "title": "options",
- "notePosition": 54,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "options",
- "isInheritable": false,
- "position": 20
- }
- ],
- "format": "markdown",
- "dataFileName": "options.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "VyFirdgAOoh5",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "VyFirdgAOoh5"
- ],
- "title": "recent_notes",
- "notePosition": 55,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "DSkl8C325tEC",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "recent-notes",
- "isInheritable": false,
- "position": 20
- }
- ],
- "format": "markdown",
- "dataFileName": "recent_notes.md",
- "attachments": []
- },
- {
- "isClone": false,
- "noteId": "s7ZBiaJVNumK",
- "notePath": [
- "jdjRLhLV3TtI",
- "yeqU0zo0ZQ83",
- "vNMojjUN76jc",
- "s7ZBiaJVNumK"
- ],
- "title": "revisions",
- "notePosition": 56,
- "prefix": null,
- "isExpanded": false,
- "type": "text",
- "mime": "text/html",
- "attributes": [
- {
- "type": "relation",
- "name": "internalLink",
- "value": "DSkl8C325tEC",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "VIcWnKGs0sMh",
- "isInheritable": false,
- "position": 20
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "UvXpeSqfYc6d",
- "isInheritable": false,
- "position": 30
- },
- {
- "type": "label",
- "name": "iconClass",
- "value": "bx bx-table",
- "isInheritable": false,
- "position": 10
- },
- {
- "type": "label",
- "name": "shareAlias",
- "value": "revisions",
- "isInheritable": false,
- "position": 50
- }
- ],
- "format": "markdown",
- "dataFileName": "revisions.md",
- "attachments": []
- }
- ]
- },
{
"isClone": false,
"noteId": "tM3rIZQzlum4",
@@ -1371,7 +1555,7 @@
"tM3rIZQzlum4"
],
"title": "Deleted notes",
- "notePosition": 50,
+ "notePosition": 70,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1405,7 +1589,7 @@
"oLhKpfi2kGON"
],
"title": "Demo document",
- "notePosition": 60,
+ "notePosition": 80,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1430,6 +1614,40 @@
"dataFileName": "Demo document.md",
"attachments": []
},
+ {
+ "isClone": false,
+ "noteId": "TiUll0Osoaz6",
+ "notePath": [
+ "jdjRLhLV3TtI",
+ "yeqU0zo0ZQ83",
+ "TiUll0Osoaz6"
+ ],
+ "title": "Entities",
+ "notePosition": 90,
+ "prefix": null,
+ "isExpanded": false,
+ "type": "text",
+ "mime": "text/html",
+ "attributes": [
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "entities",
+ "isInheritable": false,
+ "position": 20
+ },
+ {
+ "type": "label",
+ "name": "iconClass",
+ "value": "bx bxs-note",
+ "isInheritable": false,
+ "position": 30
+ }
+ ],
+ "format": "markdown",
+ "dataFileName": "Entities.md",
+ "attachments": []
+ },
{
"isClone": false,
"noteId": "UzRirf46Xi46",
@@ -1439,7 +1657,7 @@
"UzRirf46Xi46"
],
"title": "Hidden notes",
- "notePosition": 80,
+ "notePosition": 100,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1473,7 +1691,7 @@
"m2W35hwSDUeh"
],
"title": "Icons",
- "notePosition": 90,
+ "notePosition": 110,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1514,7 +1732,7 @@
"TLXJwBDo8Rdv"
],
"title": "Internationalisation / Translations",
- "notePosition": 100,
+ "notePosition": 120,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1649,7 +1867,7 @@
"Usiyzn9C4WFv"
],
"title": "Launchers",
- "notePosition": 110,
+ "notePosition": 130,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1676,7 +1894,7 @@
"qjQNyaYXSNWu"
],
"title": "Note Revisions",
- "notePosition": 120,
+ "notePosition": 140,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -1710,7 +1928,7 @@
"7RBJMqVz2EsJ"
],
"title": "Note Types",
- "notePosition": 130,
+ "notePosition": 150,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2044,7 +2262,7 @@
"6dC7ha5vjqqS"
],
"title": "Options",
- "notePosition": 140,
+ "notePosition": 160,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2109,7 +2327,7 @@
"W0msUwLxm40d"
],
"title": "Printing and exporting to PDF",
- "notePosition": 150,
+ "notePosition": 170,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2150,7 +2368,7 @@
"UvXpeSqfYc6d"
],
"title": "Protected entities",
- "notePosition": 160,
+ "notePosition": 180,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2205,7 +2423,7 @@
"vphziLmQeQHY"
],
"title": "Share",
- "notePosition": 170,
+ "notePosition": 190,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2239,7 +2457,7 @@
"n9wYW9nUTynV"
],
"title": "Synchronisation",
- "notePosition": 180,
+ "notePosition": 200,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2303,7 +2521,7 @@
"k7RavjuXQt8z"
],
"title": "Syntax highlighting",
- "notePosition": 190,
+ "notePosition": 210,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2337,7 +2555,7 @@
"7BCukQTCm7fv"
],
"title": "Themes",
- "notePosition": 200,
+ "notePosition": 220,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2372,7 +2590,7 @@
"YjerxU7Aii8X"
],
"title": "Troubleshooting",
- "notePosition": 360,
+ "notePosition": 370,
"prefix": null,
"isExpanded": false,
"type": "text",
@@ -2461,12 +2679,19 @@
"dtKC3FmoWOrv"
],
"title": "Testing",
- "notePosition": 380,
+ "notePosition": 390,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
+ {
+ "type": "relation",
+ "name": "internalLink",
+ "value": "w6gMvKh0UAVT",
+ "isInheritable": false,
+ "position": 10
+ },
{
"type": "label",
"name": "shareAlias",
@@ -2480,13 +2705,6 @@
"value": "bx bxs-eyedropper",
"isInheritable": false,
"position": 30
- },
- {
- "type": "relation",
- "name": "internalLink",
- "value": "w6gMvKh0UAVT",
- "isInheritable": false,
- "position": 40
}
],
"format": "markdown",
diff --git a/docs/Developer Guide/Developer Guide/Architecture.md b/docs/Developer Guide/Developer Guide/Architecture.md
new file mode 100644
index 000000000..a11d27274
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Architecture.md
@@ -0,0 +1,118 @@
+# Architecture
+Trilium Notes is a hierarchical note-taking application built as a TypeScript monorepo. It supports multiple deployment modes (desktop, server, mobile web) and features advanced capabilities including synchronization, scripting, encryption, and rich content editing.
+
+### Key Characteristics
+
+* **Monorepo Architecture**: Uses pnpm workspaces for dependency management
+* **Multi-Platform**: Desktop (Electron), Server (Node.js/Express), and Mobile Web
+* **TypeScript-First**: Strong typing throughout the codebase
+* **Plugin-Based**: Extensible architecture for note types and UI components
+* **Offline-First**: Full functionality without network connectivity
+* **Synchronization-Ready**: Built-in sync protocol for multi-device usage
+
+### Technology Stack
+
+* **Runtime**: Node.js (backend), Browser/Electron (frontend)
+* **Language**: TypeScript, JavaScript
+* **Database**: SQLite (better-sqlite3)
+* **Build Tools**: Vite, ESBuild, pnpm
+* **UI Framework**: Custom widget-based system (vanilla HTML, CSS & JavaScript + jQuery), in the process of converting to React/Preact.
+* **Rich Text**: CKEditor 5 (customized)
+* **Code Editing**: CodeMirror 6
+* **Desktop**: Electron
+* **Server**: Express.js
+
+## Main architecture
+
+Trilium follows a **client-server architecture** even in desktop mode, where Electron runs both the backend server and frontend client within the same process.
+
+```mermaid
+graph TB
+ subgraph Frontend
+ Widgets[Widgets
System]
+ Froca[Froca
Cache]
+ UIServices[UI
Services]
+ end
+
+ subgraph Backend["Backend Server"]
+ Express[Express
Routes]
+ Becca[Becca
Cache]
+ ScriptEngine[Script
Engine]
+ Database[(SQLite
Database)]
+ end
+
+ Widgets -.-> API[WebSocket & REST API]
+ Froca -.-> API
+ UIServices -.-> API
+ API -.-> Express
+ API -.-> Becca
+ API -.-> ScriptEngine
+ Becca --> Database
+ Express --> Database
+ ScriptEngine --> Database
+```
+
+### Deployment Modes
+
+1. **Desktop Application**
+ * Electron wrapper running both frontend and backend
+ * Local SQLite database
+ * Full offline functionality
+ * Cross-platform (Windows, macOS, Linux)
+2. **Server Installation**
+ * Node.js server exposing web interface
+ * Multi-user capable
+ * Can sync with desktop clients
+ * Docker deployment supported
+3. **Mobile Web**
+ * Optimized responsive interface
+ * Accessed via browser
+ * Requires server installation
+
+## Monorepo Structure
+
+Trilium uses **pnpm workspaces** to manage its monorepo structure, with apps and packages clearly separated.
+
+```
+trilium/
+├── apps/ # Runnable applications
+│ ├── client/ # Frontend application (shared by server & desktop)
+│ ├── server/ # Node.js server with web interface
+│ ├── desktop/ # Electron desktop application
+│ ├── web-clipper/ # Browser extension for web content capture
+│ ├── db-compare/ # Database comparison tool
+│ ├── dump-db/ # Database export tool
+│ ├── edit-docs/ # Documentation editing tool
+│ ├── build-docs/ # Documentation build tool
+│ └── website/ # Marketing website
+│
+├── packages/ # Shared libraries
+│ ├── commons/ # Shared interfaces and utilities
+│ ├── ckeditor5/ # Custom rich text editor
+│ ├── codemirror/ # Code editor customizations
+│ ├── highlightjs/ # Syntax highlighting
+│ ├── ckeditor5-admonition/ # CKEditor plugin: admonitions
+│ ├── ckeditor5-footnotes/ # CKEditor plugin: footnotes
+│ ├── ckeditor5-keyboard-marker/# CKEditor plugin: keyboard shortcuts
+│ ├── ckeditor5-math/ # CKEditor plugin: math equations
+│ ├── ckeditor5-mermaid/ # CKEditor plugin: diagrams
+│ ├── express-partial-content/ # HTTP partial content middleware
+│ ├── share-theme/ # Shared note theme
+│ ├── splitjs/ # Split pane library
+│ └── turndown-plugin-gfm/ # Markdown conversion
+│
+├── docs/ # Documentation
+├── scripts/ # Build and utility scripts
+└── patches/ # Package patches (via pnpm)
+```
+
+### Package Dependencies
+
+The monorepo uses workspace protocol (`workspace:*`) for internal dependencies:
+
+```
+desktop → client → commons
+server → client → commons
+client → ckeditor5, codemirror, highlightjs
+ckeditor5 → ckeditor5-* plugins
+```
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/API.md b/docs/Developer Guide/Developer Guide/Architecture/API.md
new file mode 100644
index 000000000..57fc8c164
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Architecture/API.md
@@ -0,0 +1,72 @@
+# API
+### Internal API
+
+**REST Endpoints** (`/api/*`)
+
+Used by the frontend for all operations:
+
+**Note Operations:**
+
+* `GET /api/notes/:noteId` - Get note
+* `POST /api/notes/:noteId/content` - Update content
+* `PUT /api/notes/:noteId` - Update metadata
+* `DELETE /api/notes/:noteId` - Delete note
+
+**Tree Operations:**
+
+* `GET /api/tree` - Get note tree
+* `POST /api/branches` - Create branch
+* `PUT /api/branches/:branchId` - Update branch
+* `DELETE /api/branches/:branchId` - Delete branch
+
+**Search:**
+
+* `GET /api/search?query=...` - Search notes
+* `GET /api/search-note/:noteId` - Execute search note
+
+### ETAPI (External API)
+
+Located at: `apps/server/src/etapi/`
+
+**Purpose:** Third-party integrations and automation
+
+**Authentication:** Token-based (ETAPI tokens)
+
+**OpenAPI Spec:** Auto-generated
+
+**Key Endpoints:**
+
+* `/etapi/notes` - Note CRUD
+* `/etapi/branches` - Branch management
+* `/etapi/attributes` - Attribute operations
+* `/etapi/attachments` - Attachment handling
+
+**Example:**
+
+```sh
+curl -H "Authorization: YOUR_TOKEN" \
+ https://trilium.example.com/etapi/notes/noteId
+```
+
+### WebSocket API
+
+Located at: `apps/server/src/services/ws.ts`
+
+**Purpose:** Real-time updates and synchronization
+
+**Protocol:** WebSocket (Socket.IO-like custom protocol)
+
+**Message Types:**
+
+* `sync` - Synchronization request
+* `entity-change` - Entity update notification
+* `refresh-tree` - Tree structure changed
+* `open-note` - Open note in UI
+
+**Client Subscribe:**
+
+```typescript
+ws.subscribe('entity-change', (data) => {
+ froca.processEntityChange(data)
+})
+```
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Backend.md b/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Backend.md
new file mode 100644
index 000000000..df0ddf21d
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Backend.md
@@ -0,0 +1,88 @@
+# Backend
+### Application Entry Point
+
+Location: `apps/server/src/main.ts`
+
+**Startup Sequence:**
+
+1. Load configuration
+2. Initialize database
+3. Run migrations
+4. Load Becca cache
+5. Start Express server
+6. Initialize WebSocket
+7. Start scheduled tasks
+
+### Service Layer
+
+Located at: `apps/server/src/services/`
+
+**Core Services:**
+
+* **Notes Management**
+ * `notes.ts` - CRUD operations
+ * `note_contents.ts` - Content handling
+ * `note_types.ts` - Type-specific logic
+ * `cloning.ts` - Note cloning/multi-parent
+* **Tree Operations**
+ * `tree.ts` - Tree structure management
+ * `branches.ts` - Branch operations
+ * `consistency_checks.ts` - Tree integrity
+* **Search**
+ * `search/search.ts` - Main search engine
+ * `search/expressions/` - Search expression parsing
+ * `search/services/` - Search utilities
+* **Sync**
+ * `sync.ts` - Synchronization protocol
+ * `sync_update.ts` - Update handling
+ * `sync_mutex.ts` - Concurrency control
+* **Scripting**
+ * `backend_script_api.ts` - Backend script API
+ * `script_context.ts` - Script execution context
+* **Import/Export**
+ * `import/` - Various import formats
+ * `export/` - Export to different formats
+ * `zip.ts` - Archive handling
+* **Security**
+ * `encryption.ts` - Note encryption
+ * `protected_session.ts` - Session management
+ * `password.ts` - Password handling
+
+### Route Structure
+
+Located at: `apps/server/src/routes/`
+
+```
+routes/
+├── index.ts # Route registration
+├── api/ # REST API endpoints
+│ ├── notes.ts
+│ ├── branches.ts
+│ ├── attributes.ts
+│ ├── search.ts
+│ ├── login.ts
+│ └── ...
+└── custom/ # Special endpoints
+ ├── setup.ts
+ ├── share.ts
+ └── ...
+```
+
+**API Endpoint Pattern:**
+
+```typescript
+router.get('/api/notes/:noteId', (req, res) => {
+ const noteId = req.params.noteId
+ const note = becca.getNote(noteId)
+ res.json(note.getPojoWithContent())
+})
+```
+
+### Middleware
+
+Key middleware components:
+
+* `auth.ts` - Authentication
+* `csrf.ts` - CSRF protection
+* `request_context.ts` - Request-scoped data
+* `error_handling.ts` - Error responses
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Frontend.md b/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Frontend.md
new file mode 100644
index 000000000..9ef0acbdf
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Architecture/Client-server architecture/Frontend.md
@@ -0,0 +1,61 @@
+# Frontend
+### Application Entry Point
+
+**Desktop:** `apps/client/src/desktop.ts` **Web:** `apps/client/src/index.ts`
+
+### Service Layer
+
+Located at: `apps/client/src/services/`
+
+Key services:
+
+* `froca.ts` - Frontend cache
+* `server.ts` - API communication
+* `ws.ts` - WebSocket connection
+* `tree_service.ts` - Note tree management
+* `note_context.ts` - Active note tracking
+* `protected_session.ts` - Encryption key management
+* `link.ts` - Note linking and navigation
+* `export.ts` - Note export functionality
+
+### UI Components
+
+**Component Locations:**
+
+* `widgets/containers/` - Layout containers
+* `widgets/buttons/` - Toolbar buttons
+* `widgets/dialogs/` - Modal dialogs
+* `widgets/ribbon_widgets/` - Tab widgets
+* `widgets/type_widgets/` - Note type editors
+
+### Event System
+
+**Application Events:**
+
+```typescript
+// Subscribe to events
+appContext.addBeforeUnloadListener(() => {
+ // Cleanup before page unload
+})
+
+// Trigger events
+appContext.trigger('noteTreeLoaded')
+```
+
+**Note Context Events:**
+
+```typescript
+// NoteContextAwareWidget automatically receives:
+- noteSwitched()
+- noteChanged()
+- refresh()
+```
+
+### State Management
+
+Trilium uses **custom state management** rather than Redux/MobX:
+
+* `note_context.ts` - Active note and context
+* `froca.ts` - Entity cache
+* Component local state
+* URL parameters for shareable state
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database.md b/docs/Developer Guide/Developer Guide/Architecture/Database.md
new file mode 100644
index 000000000..bb80ccdb1
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database.md
@@ -0,0 +1,40 @@
+# Database
+Trilium uses **SQLite** as its database engine, managed via `better-sqlite3`.
+
+Schema location: `apps/server/src/assets/db/schema.sql`
+
+### Data Access Patterns
+
+**Direct SQL:**
+
+```typescript
+// apps/server/src/services/sql.ts
+sql.getRows("SELECT * FROM notes WHERE type = ?", ['text'])
+sql.execute("UPDATE notes SET title = ? WHERE noteId = ?", [title, noteId])
+```
+
+**Through Becca:**
+
+```typescript
+// Recommended approach - uses cache
+const note = becca.getNote('noteId')
+note.title = 'New Title'
+note.save()
+```
+
+**Through Froca (Frontend):**
+
+```typescript
+// Read-only access
+const note = froca.getNote('noteId')
+console.log(note.title)
+```
+
+### Database Migrations
+
+* The migration system is in `server/src/migrations/migrations.ts` (actual definitions) and `src/services/migration.ts`.
+* Both SQLite and TypeScript migrations are supported.
+ * Small migrations are contained directly in `src/migrations/migrations.ts`.
+ * Bigger TypeScript migrations are sequentially numbered (e.g., `XXXX_migration_name.ts`) and dynamically imported by `migrations.ts`.
+* Automatic execution on version upgrade.
+* Schema version tracked in options table.
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md
similarity index 90%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md
index 4312832dd..09ae80d4b 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attachments.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attachments.md
@@ -6,11 +6,11 @@
| `role` | Text | Non-null | | The role of the attachment: `image` for images that are attached to a note, `file` for uploaded files. |
| `mime` | Text | Non-null | | The MIME type of the attachment (e.g. `image/png`) |
| `title` | Text | Non-null | | The title of the attachment. |
-| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. |
+| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. |
| `position` | Integer | Non-null | 0 | Not sure where the position is relevant for attachments (saw it with values of 10 and 0). |
| `blobId` | Text | Nullable | `null` | The corresponding `blobId` from the blobs table. |
| `dateModified` | Text | Non-null | | Localized modification date (e.g. `2023-11-08 18:43:44.204+0200`) |
| `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) |
| `utcDateScheduledForErasure` | Text | Nullable | `null` | |
-| `isDeleted` | Integer | Non-null | | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. |
+| `isDeleted` | Integer | Non-null | | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. |
| `deleteId` | Text | Nullable | `null` | |
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md
similarity index 84%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md
index 959073ec8..f1cbb99c4 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/attributes.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/attributes.md
@@ -1,2 +1,2 @@
# attributes
-Column Name Data Type Nullity Default value Description attributeIdText Non-null Unique Id of the attribute (e.g. qhC1vzU4nwSE), can also have a special unique ID for Special notes (e.g. _lbToday_liconClass). noteIdText Non-null The ID of the note this atttribute belongs to typeText Non-null The type of attribute (label or relation). nameText Non-null The name/key of the attribute. valueText Non-null ""- For
label attributes, a free-form value of the attribute. - For
relation attributes, the ID of the note the relation is pointing to.
positionInteger Non-null 0 The position of the attribute compared to the other attributes. Some predefined attributes such as originalFileName have a value of 1000. utcDateModifiedText Non-null Modification date in UTC format (e.g. 2023-11-08 16:43:44.204Z) isDeletedInteger Non-null 1 if the entity is deleted, 0 otherwise.deleteIdText Nullable null isInheritableInteger Nullable 0
\ No newline at end of file
+Column Name Data Type Nullity Default value Description attributeIdText Non-null Unique Id of the attribute (e.g. qhC1vzU4nwSE), can also have a special unique ID for Special notes (e.g. _lbToday_liconClass). noteIdText Non-null The ID of the note this atttribute belongs to typeText Non-null The type of attribute (label or relation). nameText Non-null The name/key of the attribute. valueText Non-null ""- For
label attributes, a free-form value of the attribute. - For
relation attributes, the ID of the note the relation is pointing to.
positionInteger Non-null 0 The position of the attribute compared to the other attributes. Some predefined attributes such as originalFileName have a value of 1000. utcDateModifiedText Non-null Modification date in UTC format (e.g. 2023-11-08 16:43:44.204Z) isDeletedInteger Non-null 1 if the entity is deleted, 0 otherwise.deleteIdText Nullable null isInheritableInteger Nullable 0
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/blobs.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/blobs.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/blobs.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/blobs.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md
similarity index 82%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md
index d9b12dea5..18cf29090 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/branches.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/branches.md
@@ -5,8 +5,8 @@
| `noteId` | Text | Non-null | | The ID of the [note](notes.md). |
| `parentNoteId` | Text | Non-null | | The ID of the parent [note](notes.md) the note belongs to. |
| `notePosition` | Integer | Non-null | | The position of the branch within the same level of hierarchy, the value is usually a multiple of 10. |
-| `prefix` | Text | Nullable | | The [branch prefix](../Branch%20prefixes.md) if any, or `NULL` otherwise. |
+| `prefix` | Text | Nullable | | The [branch prefix](../../../Concepts/Branch%20prefixes.md) if any, or `NULL` otherwise. |
| `isExpanded` | Integer | Non-null | 0 | Whether the branch should appear expanded (its children shown) to the user. |
-| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. |
+| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. |
| `deleteId` | Text | Nullable | `null` | |
| `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) |
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/entity_changes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/entity_changes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/entity_changes.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/entity_changes.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md
similarity index 90%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md
index 25fe4e5da..3f11dffa9 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/etapi_tokens.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/etapi_tokens.md
@@ -6,4 +6,4 @@
| `tokenHash` | Text | Non-null | | The token itself. |
| `utcDateCreated` | Text | Non-null | | Creation date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) |
| `utcDateModified` | Text | Non-null | | Modification date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) |
-| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. |
\ No newline at end of file
+| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. |
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md
similarity index 90%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md
index 572c7f6db..19cb4a322 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/notes.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/notes.md
@@ -3,10 +3,10 @@
| --- | --- | --- | --- | --- |
| `noteId` | Text | Non-null | | The unique ID of the note (e.g. `2LJrKqIhr0Pe`). |
| `title` | Text | Non-null | `"note"` | The title of the note, as defined by the user. |
-| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. |
+| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. |
| `type` | Text | Non-null | `"text"` | The type of note (i.e. `text`, `file`, `code`, `relationMap`, `mermaid`, `canvas`). |
| `mime` | Text | Non-null | `"text/html"` | The MIME type of the note (e.g. `text/html`).. Note that it can be an empty string in some circumstances, but not null. |
-| `isDeleted` | Integer | Nullable | 0 | `1` if the entity is [deleted](../Deleted%20notes.md), `0` otherwise. |
+| `isDeleted` | Integer | Nullable | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. |
| `deleteId` | Text | Non-null | `null` | |
| `dateCreated` | Text | Non-null | | Localized creation date (e.g. `2023-11-08 18:43:44.204+0200`) |
| `dateModified` | Text | Non-null | | Localized modification date (e.g. `2023-11-08 18:43:44.204+0200`) |
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/options.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/options.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/options.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/options.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/recent_notes.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/recent_notes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/recent_notes.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/recent_notes.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md
similarity index 94%
rename from docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md
rename to docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md
index 210e05356..fef9ed1ed 100644
--- a/docs/Developer Guide/Developer Guide/Architecture/Database structure/revisions.md
+++ b/docs/Developer Guide/Developer Guide/Architecture/Database/Database structure/revisions.md
@@ -6,7 +6,7 @@
| `type` | Text | Non-null | `""` | The type of note (i.e. `text`, `file`, `code`, `relationMap`, `mermaid`, `canvas`). |
| `mime` | Text | Non-null | `""` | The MIME type of the note (e.g. `text/html`). |
| `title` | Text | Non-null | | The title of the note, as defined by the user. |
-| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../Protected%20entities.md), `0` otherwise. |
+| `isProtected` | Integer | Non-null | 0 | `1` if the entity is [protected](../../../Concepts/Protected%20entities.md), `0` otherwise. |
| `blobId` | Text | Nullable | `null` | The corresponding ID from blobs. Although it can theoretically be `NULL`, haven't found any such note yet. |
| `utcDateLastEdited` | Text | Non-null | | **Not sure how it differs from modification date.** |
| `utcDateCreated` | Text | Non-null | | Creation date in UTC format (e.g. `2023-11-08 16:43:44.204Z`) |
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md b/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md
deleted file mode 100644
index f7d4e5b2e..000000000
--- a/docs/Developer Guide/Developer Guide/Architecture/Protected entities.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Protected entities
-The following entities can be made protected, via their `isProtected` flag:
-
-* attachments
-* notes
-* revisions
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Backlinks.md b/docs/Developer Guide/Developer Guide/Concepts/Backlinks.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Backlinks.md
rename to docs/Developer Guide/Developer Guide/Concepts/Backlinks.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Branch prefixes.md b/docs/Developer Guide/Developer Guide/Concepts/Branch prefixes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Branch prefixes.md
rename to docs/Developer Guide/Developer Guide/Concepts/Branch prefixes.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/1_Main_image.png b/docs/Developer Guide/Developer Guide/Concepts/CI/1_Main_image.png
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/CI/1_Main_image.png
rename to docs/Developer Guide/Developer Guide/Concepts/CI/1_Main_image.png
diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/Main.md b/docs/Developer Guide/Developer Guide/Concepts/CI/Main.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/CI/Main.md
rename to docs/Developer Guide/Developer Guide/Concepts/CI/Main.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/CI/Main_image.png b/docs/Developer Guide/Developer Guide/Concepts/CI/Main_image.png
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/CI/Main_image.png
rename to docs/Developer Guide/Developer Guide/Concepts/CI/Main_image.png
diff --git a/docs/Developer Guide/Developer Guide/Concepts/Cache.md b/docs/Developer Guide/Developer Guide/Concepts/Cache.md
new file mode 100644
index 000000000..91a6f8b6d
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Concepts/Cache.md
@@ -0,0 +1,111 @@
+# Cache
+### Three-Layer Cache System
+
+Trilium implements a sophisticated **three-tier caching system** to optimize performance and enable offline functionality:
+
+#### 1\. Becca (Backend Cache)
+
+Located at: `apps/server/src/becca/`
+
+```typescript
+// Becca caches all entities in memory
+class Becca {
+ notes: Record
+ branches: Record
+ attributes: Record
+ attachments: Record
+ // ... other entity collections
+}
+```
+
+**Responsibilities:**
+
+* Server-side entity cache
+* Maintains complete note tree in memory
+* Handles entity relationships and integrity
+* Provides fast lookups without database queries
+* Manages entity lifecycle (create, update, delete)
+
+**Key Files:**
+
+* `becca.ts` - Main cache instance
+* `becca_loader.ts` - Loads entities from database
+* `becca_service.ts` - Cache management operations
+* `entities/` - Entity classes (BNote, BBranch, etc.)
+
+#### 2\. Froca (Frontend Cache)
+
+Located at: `apps/client/src/services/froca.ts`
+
+```typescript
+// Froca is a read-only mirror of backend data
+class Froca {
+ notes: Record
+ branches: Record
+ attributes: Record
+ // ... other entity collections
+}
+```
+
+**Responsibilities:**
+
+* Frontend read-only cache
+* Lazy loading of note tree
+* Minimizes API calls
+* Enables fast UI rendering
+* Synchronizes with backend via WebSocket
+
+**Loading Strategy:**
+
+* Initial load: root notes and immediate children
+* Lazy load: notes loaded when accessed
+* When note is loaded, all parent and child branches load
+* Deleted entities tracked via missing branches
+
+#### 3\. Shaca (Share Cache)
+
+Located at: `apps/server/src/share/`
+
+**Responsibilities:**
+
+* Optimized cache for shared/published notes
+* Handles public note access without authentication
+* Performance-optimized for high-traffic scenarios
+* Separate from main Becca to isolate concerns
+
+### Cache Invalidation
+
+**Server-Side:**
+
+* Entities automatically update cache on save
+* WebSocket broadcasts changes to all clients
+* Synchronization updates trigger cache refresh
+
+**Client-Side:**
+
+* WebSocket listeners update Froca
+* Manual reload via `froca.loadSubTree(noteId)`
+* Full reload on protected session changes
+
+### Cache Consistency
+
+**Entity Change Tracking:**
+
+```typescript
+// Every entity modification tracked
+entity_changes (
+ entityName: 'notes',
+ entityId: 'note123',
+ hash: 'abc...',
+ changeId: 'change456',
+ utcDateChanged: '2025-11-02...'
+)
+```
+
+**Sync Protocol:**
+
+1. Client requests changes since last sync
+2. Server returns entity\_changes records
+3. Client applies changes to Froca
+4. Client sends local changes to server
+5. Server updates Becca and database
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Deleted notes.md b/docs/Developer Guide/Developer Guide/Concepts/Deleted notes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Deleted notes.md
rename to docs/Developer Guide/Developer Guide/Concepts/Deleted notes.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Demo document.md b/docs/Developer Guide/Developer Guide/Concepts/Demo document.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Demo document.md
rename to docs/Developer Guide/Developer Guide/Concepts/Demo document.md
diff --git a/docs/Developer Guide/Developer Guide/Concepts/Entities.md b/docs/Developer Guide/Developer Guide/Concepts/Entities.md
new file mode 100644
index 000000000..56d954c94
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Concepts/Entities.md
@@ -0,0 +1,109 @@
+# Entities
+### Entity System
+
+Trilium's data model is based on five core entities:
+
+```mermaid
+graph TD
+ Note[Note
BNote]
+ Branch[Branch
BBranch]
+ Attribute[Attribute
BAttribute]
+ Revision[Revision
BRevision]
+ Attachment[Attachment
BAttachment]
+
+ Note -->|linked by| Branch
+ Note -.->|metadata| Attribute
+ Branch -->|creates| Revision
+ Note -->|has| Attachment
+
+ style Note fill:#e1f5ff
+ style Branch fill:#fff4e1
+ style Attribute fill:#ffe1f5
+ style Revision fill:#f5ffe1
+ style Attachment fill:#ffe1e1
+```
+
+#### Entity Definitions
+
+**1\. BNote** (`apps/server/src/becca/entities/bnote.ts`)
+
+* Represents a note with title, content, and metadata
+* Type can be: text, code, file, image, canvas, mermaid, etc.
+* Contains content via blob reference
+* Can be protected (encrypted)
+* Has creation and modification timestamps
+
+**2\. BBranch** (`apps/server/src/becca/entities/bbranch.ts`)
+
+* Represents parent-child relationship between notes
+* Enables note cloning (multiple parents)
+* Contains positioning information
+* Has optional prefix for customization
+* Tracks expansion state in tree
+
+**3\. BAttribute** (`apps/server/src/becca/entities/battribute.ts`)
+
+* Key-value metadata attached to notes
+* Two types: labels (tags) and relations (links)
+* Can be inheritable to child notes
+* Used for search, organization, and scripting
+* Supports promoted attributes (displayed prominently)
+
+**4\. BRevision** (`apps/server/src/becca/entities/brevision.ts`)
+
+* Stores historical versions of note content
+* Automatic versioning on edits
+* Retains title, type, and content
+* Enables note history browsing and restoration
+
+**5\. BAttachment** (`apps/server/src/becca/entities/battachment.ts`)
+
+* File attachments linked to notes
+* Has owner (note), role, and mime type
+* Content stored in blobs
+* Can be protected (encrypted)
+
+**6\. BBlob** (`apps/server/src/becca/entities/bblob.ts`)
+
+* Binary large object storage
+* Stores actual note content and attachments
+* Referenced by notes, revisions, and attachments
+* Supports encryption for protected content
+
+### Widget-Based UI
+
+The frontend uses a **widget system** for modular, reusable UI components.
+
+Located at: `apps/client/src/widgets/`
+
+```typescript
+// Widget Hierarchy
+BasicWidget
+├── NoteContextAwareWidget (responds to note changes)
+│ ├── RightPanelWidget (displayed in right sidebar)
+│ └── Type-specific widgets
+├── Container widgets (tabs, ribbons, etc.)
+└── Specialized widgets (search, calendar, etc.)
+```
+
+**Base Classes:**
+
+1. **BasicWidget** (`basic_widget.ts`)
+ * Base class for all UI components
+ * Lifecycle: construction → rendering → events → destruction
+ * Handles DOM manipulation
+ * Event subscription management
+ * Child widget management
+2. **NoteContextAwareWidget** (`note_context_aware_widget.ts`)
+ * Extends BasicWidget
+ * Automatically updates when active note changes
+ * Accesses current note context
+ * Used for note-dependent UI
+3. **RightPanelWidget**
+ * Widgets displayed in right sidebar
+ * Collapsible sections
+ * Context-specific tools and information
+
+**Type-Specific Widgets:**
+
+Each note type has a dedicated widget, which are located in `apps/client/src/widgets/type_widgets`.
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Hidden notes.md b/docs/Developer Guide/Developer Guide/Concepts/Hidden notes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Hidden notes.md
rename to docs/Developer Guide/Developer Guide/Concepts/Hidden notes.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Icons.md b/docs/Developer Guide/Developer Guide/Concepts/Icons.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Icons.md
rename to docs/Developer Guide/Developer Guide/Concepts/Icons.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translat.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translat.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translat.md
rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translat.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Guidelines.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Guidelines.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Guidelines.md
rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Guidelines.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Server translations.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Server translations.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/Server translations.md
rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/Server translations.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/i18n-ally.md b/docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/i18n-ally.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Internationalisation Translations/i18n-ally.md
rename to docs/Developer Guide/Developer Guide/Concepts/Internationalisation Translations/i18n-ally.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Launchers.md b/docs/Developer Guide/Developer Guide/Concepts/Launchers.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Launchers.md
rename to docs/Developer Guide/Developer Guide/Concepts/Launchers.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Revisions.md b/docs/Developer Guide/Developer Guide/Concepts/Note Revisions.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Revisions.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Revisions.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Copy image reference to the cl.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Copy image reference to the cl.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Copy image reference to the cl.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Copy image reference to the cl.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Export diagram as SVG.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Export diagram as SVG.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Export diagram as SVG.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Export diagram as SVG.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps/mind_map.js b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps/mind_map.js
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/First steps/mind_map.js
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/First steps/mind_map.js
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Loading data.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Loading data.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Loading data.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Loading data.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Note type checklist.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Note type checklist.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Note type checklist.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Note type checklist.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/SVG rendering.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/SVG rendering.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/SVG rendering.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/SVG rendering.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Saving data via spaced update.md b/docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Saving data via spaced update.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Note Types/Adding a new note type/Saving data via spaced update.md
rename to docs/Developer Guide/Developer Guide/Concepts/Note Types/Adding a new note type/Saving data via spaced update.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Options.md b/docs/Developer Guide/Developer Guide/Concepts/Options.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Options.md
rename to docs/Developer Guide/Developer Guide/Concepts/Options.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Options/Creating a new option.md b/docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Options/Creating a new option.md
rename to docs/Developer Guide/Developer Guide/Concepts/Options/Creating a new option.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Printing and exporting to PDF.md b/docs/Developer Guide/Developer Guide/Concepts/Printing and exporting to PDF.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Printing and exporting to PDF.md
rename to docs/Developer Guide/Developer Guide/Concepts/Printing and exporting to PDF.md
diff --git a/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md b/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md
new file mode 100644
index 000000000..31d5250c0
--- /dev/null
+++ b/docs/Developer Guide/Developer Guide/Concepts/Protected entities.md
@@ -0,0 +1,6 @@
+# Protected entities
+The following entities can be made protected, via their `isProtected` flag:
+
+* attachments
+* notes
+* revisions
\ No newline at end of file
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Share.md b/docs/Developer Guide/Developer Guide/Concepts/Share.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Share.md
rename to docs/Developer Guide/Developer Guide/Concepts/Share.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Synchronisation/Content hashing.md b/docs/Developer Guide/Developer Guide/Concepts/Synchronisation/Content hashing.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Synchronisation/Content hashing.md
rename to docs/Developer Guide/Developer Guide/Concepts/Synchronisation/Content hashing.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Syntax highlighting.md b/docs/Developer Guide/Developer Guide/Concepts/Syntax highlighting.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Syntax highlighting.md
rename to docs/Developer Guide/Developer Guide/Concepts/Syntax highlighting.md
diff --git a/docs/Developer Guide/Developer Guide/Architecture/Themes.md b/docs/Developer Guide/Developer Guide/Concepts/Themes.md
similarity index 100%
rename from docs/Developer Guide/Developer Guide/Architecture/Themes.md
rename to docs/Developer Guide/Developer Guide/Concepts/Themes.md
diff --git a/docs/Developer Guide/Developer Guide/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md
index 4874aaa1d..611bdd69a 100644
--- a/docs/Developer Guide/Developer Guide/Documentation.md
+++ b/docs/Developer Guide/Developer Guide/Documentation.md
@@ -1,5 +1,5 @@
# Documentation
-There are multiple types of documentation for Trilium:
+There are multiple types of documentation for Trilium:
* The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1.
* The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.
diff --git a/docs/Developer Guide/Developer Guide/Environment Setup.md b/docs/Developer Guide/Developer Guide/Environment Setup.md
index 95d14cd50..bf7f44adb 100644
--- a/docs/Developer Guide/Developer Guide/Environment Setup.md
+++ b/docs/Developer Guide/Developer Guide/Environment Setup.md
@@ -33,4 +33,4 @@ Run `pnpm i` at the top of the `Notes` repository to install the dependencies.
Our recommended IDE for working on Trilium is Visual Studio Code (or VSCodium if you are looking for a fully open-source alternative).
-By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing or for Internationalisation / Translations.
\ No newline at end of file
+By default we include a number of suggested extensions which should appear when opening the repository in VS Code. Most of the extensions are for integrating various technologies we are using such as Playwright and Vitest for testing or for Internationalisation / Translations.
\ No newline at end of file
diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json
index a38998354..0a573e808 100644
--- a/docs/User Guide/!!!meta.json
+++ b/docs/User Guide/!!!meta.json
@@ -14616,21 +14616,21 @@
{
"type": "relation",
"name": "internalLink",
- "value": "zEY4DaJG4YT5",
+ "value": "GLks18SNjxmC",
"isInheritable": false,
"position": 10
},
{
"type": "relation",
"name": "internalLink",
- "value": "SynTBQiBsdYJ",
+ "value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
- "value": "GLks18SNjxmC",
+ "value": "SynTBQiBsdYJ",
"isInheritable": false,
"position": 30
},
@@ -14787,19 +14787,19 @@
"isInheritable": false,
"position": 30
},
- {
- "type": "label",
- "name": "shareAlias",
- "value": "widget-basics",
- "isInheritable": false,
- "position": 20
- },
{
"type": "relation",
"name": "internalLink",
"value": "s8alTXmpFR61",
"isInheritable": false,
"position": 40
+ },
+ {
+ "type": "label",
+ "name": "shareAlias",
+ "value": "widget-basics",
+ "isInheritable": false,
+ "position": 20
}
],
"format": "markdown",
@@ -14949,21 +14949,21 @@
{
"type": "relation",
"name": "internalLink",
- "value": "m1lbrzyKDaRB",
+ "value": "yIhgI5H7A2Sm",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
- "value": "s8alTXmpFR61",
+ "value": "m1lbrzyKDaRB",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
- "value": "yIhgI5H7A2Sm",
+ "value": "s8alTXmpFR61",
"isInheritable": false,
"position": 70
},