docs(dev): integrate some of the architecture notes

This commit is contained in:
Elian Doran
2025-11-04 15:51:54 +02:00
parent 579b2ce76e
commit 58ac325634
67 changed files with 1428 additions and 1353 deletions

View File

@@ -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<br/>System]
Froca[Froca<br/>Cache]
UIServices[UI<br/>Services]
end
subgraph Backend["Backend Server"]
Express[Express<br/>Routes]
Becca[Becca<br/>Cache]
ScriptEngine[Script<br/>Engine]
Database[(SQLite<br/>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
```

View File

@@ -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)
})
```

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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 <a class="reference-link" href="blobs.md">blobs</a> 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` | |

View File

@@ -1,2 +1,2 @@
# attributes
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>attributeId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Unique Id of the attribute (e.g. <code>qhC1vzU4nwSE</code>), can also have a special unique ID for&nbsp;<a class="reference-link" href="#root/r11Bh3uxFGRj">Special notes</a>&nbsp;(e.g. <code>_lbToday_liconClass</code>).</td></tr><tr><th><code>noteId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The ID of the <a href="notes.md">note</a> this atttribute belongs to</td></tr><tr><th><code>type</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The type of attribute (<code>label</code> or <code>relation</code>).</td></tr><tr><th><code>name</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The name/key of the attribute.</td></tr><tr><th><code>value</code></th><td>Text</td><td>Non-null</td><td><code>""</code></td><td><ul><li>For <code>label</code> attributes, a free-form value of the attribute.</li><li>For <code>relation</code> attributes, the ID of the <a href="notes.md">note</a> the relation is pointing to.</li></ul></td></tr><tr><th><code>position</code></th><td>Integer</td><td>Non-null</td><td>0</td><td>The position of the attribute compared to the other attributes. Some predefined attributes such as <code>originalFileName</code> have a value of 1000.</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Modification date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>)</td></tr><tr><th><code>isDeleted</code></th><td>Integer</td><td>Non-null</td><td>&nbsp;</td><td><code>1</code> if the entity is <a href="../Deleted%20notes.md">deleted</a>, <code>0</code> otherwise.</td></tr><tr><th><code>deleteId</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td>&nbsp;</td></tr><tr><th><code>isInheritable</code></th><td>Integer</td><td>Nullable</td><td>0</td><td>&nbsp;</td></tr></tbody></table>
<table><thead><tr><th>Column Name</th><th>Data Type</th><th>Nullity</th><th>Default value</th><th>Description</th></tr></thead><tbody><tr><th><code>attributeId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Unique Id of the attribute (e.g. <code>qhC1vzU4nwSE</code>), can also have a special unique ID for&nbsp;<a class="reference-link" href="#root/r11Bh3uxFGRj">Special notes</a>&nbsp;(e.g. <code>_lbToday_liconClass</code>).</td></tr><tr><th><code>noteId</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The ID of the <a href="notes.md">note</a> this atttribute belongs to</td></tr><tr><th><code>type</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The type of attribute (<code>label</code> or <code>relation</code>).</td></tr><tr><th><code>name</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>The name/key of the attribute.</td></tr><tr><th><code>value</code></th><td>Text</td><td>Non-null</td><td><code>""</code></td><td><ul><li>For <code>label</code> attributes, a free-form value of the attribute.</li><li>For <code>relation</code> attributes, the ID of the <a href="notes.md">note</a> the relation is pointing to.</li></ul></td></tr><tr><th><code>position</code></th><td>Integer</td><td>Non-null</td><td>0</td><td>The position of the attribute compared to the other attributes. Some predefined attributes such as <code>originalFileName</code> have a value of 1000.</td></tr><tr><th><code>utcDateModified</code></th><td>Text</td><td>Non-null</td><td>&nbsp;</td><td>Modification date in UTC format (e.g. <code>2023-11-08 16:43:44.204Z</code>)</td></tr><tr><th><code>isDeleted</code></th><td>Integer</td><td>Non-null</td><td>&nbsp;</td><td><code>1</code> if the entity is <a href="../../../Concepts/Deleted%20notes.md">deleted</a>, <code>0</code> otherwise.</td></tr><tr><th><code>deleteId</code></th><td>Text</td><td>Nullable</td><td><code>null</code></td><td>&nbsp;</td></tr><tr><th><code>isInheritable</code></th><td>Integer</td><td>Nullable</td><td>0</td><td>&nbsp;</td></tr></tbody></table>

View File

@@ -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`) |

View File

@@ -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. |
| `isDeleted` | Integer | Non-null | 0 | `1` if the entity is [deleted](../../../Concepts/Deleted%20notes.md), `0` otherwise. |

View File

@@ -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`) |

View File

@@ -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 <a class="reference-link" href="blobs.md">blobs</a>. 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`) |

View File

@@ -1,6 +0,0 @@
# Protected entities
The following entities can be made protected, via their `isProtected` flag:
* <a class="reference-link" href="Database%20structure/attachments.md">attachments</a>
* <a class="reference-link" href="Database%20structure/notes.md">notes</a>
* <a class="reference-link" href="Database%20structure/revisions.md">revisions</a>

View File

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -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<string, BNote>
branches: Record<string, BBranch>
attributes: Record<string, BAttribute>
attachments: Record<string, BAttachment>
// ... 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<string, FNote>
branches: Record<string, FBranch>
attributes: Record<string, FAttribute>
// ... 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

View File

@@ -0,0 +1,109 @@
# Entities
### Entity System
Trilium's data model is based on five core entities:
```mermaid
graph TD
Note[Note<br/>BNote]
Branch[Branch<br/>BBranch]
Attribute[Attribute<br/>BAttribute]
Revision[Revision<br/>BRevision]
Attachment[Attachment<br/>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`.

View File

@@ -0,0 +1,6 @@
# Protected entities
The following entities can be made protected, via their `isProtected` flag:
* <a class="reference-link" href="../Architecture/Database/Database%20structure/attachments.md">attachments</a>
* <a class="reference-link" href="../Architecture/Database/Database%20structure/notes.md">notes</a>
* <a class="reference-link" href="../Architecture/Database/Database%20structure/revisions.md">revisions</a>

View File

@@ -1,5 +1,5 @@
# Documentation
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/attachments/2bUrJyt2yfsd/image/Documentation_image.png" width="205" height="162">
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/GUwY9NTWQZlI/Documentation_image.png" width="205" height="162">
* The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing <kbd>F1</kbd>.
* The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.

View File

@@ -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 <a class="reference-link" href="Architecture/Internationalisation%20%20Translat.md">Internationalisation / Translations</a>.
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 <a class="reference-link" href="Concepts/Internationalisation%20%20Translat.md">Internationalisation / Translations</a>.