Persistence
Trufos persists data to the file system to ensure user work is saved across sessions and to facilitate version control. The persistence layer is primarily managed by services in the main process.
Core Persistence Services
PersistenceService
(src/main/persistence/service/persistence-service.ts
):- Role: The central service for all file system operations related to collections, folders, and requests.
- Storage Strategy:
- Each Trufos object (Collection, Folder, Request) generally corresponds to a directory on the file system.
- Metadata for each object is stored in a JSON file within its directory (e.g.,
collection.json
,folder.json
,request.json
). - Text-based request bodies are stored in separate files (e.g.,
request-body.txt
).
- Key Operations:
- Loading:
loadCollection(dirPath, recursive?)
: Loads a collection from a given directory. Can load recursively (all children) or just the collection’s metadata.loadFolder(parentId, dirPath)
: Loads a folder.loadRequest(parentId, dirPath)
: Loads a request.loadTextBodyOfRequest(request, encoding?)
: Streams the text body of a request.
- Saving:
saveCollection(collection)
: Saves collection metadata.saveFolder(folder)
: Saves folder metadata.saveRequest(request, textBody?)
: Saves request metadata and optionally its text body. Handles draft versions by prefixing filenames with~
.saveCollectionRecursive(collection)
: Saves an entire collection and all its children.
- Draft Management:
saveChanges(request)
: Promotes a draft request’s files (metadata and body) to become the primary files, deleting the draft versions.discardChanges(request)
: Deletes draft files, reverting to the last saved non-draft state.
- File/Directory Management:
createDefaultCollectionIfNotExists()
: Ensures a default collection exists for new users.createCollection(dirPath, title)
: Creates a new, empty collection structure.rename(object, newTitle)
: Renames an object and its corresponding directory.delete(object)
: Deletes an object and its directory, including all children recursively.moveChild(child, oldParent, newParent)
: Moves an object’s directory between parent directories.
- Loading:
- Path Mapping: Maintains an internal
idToPathMap
to track the file system path for each object ID, which is crucial for locating objects when their titles (and thus directory names) change. - Directory Naming: Directory names are derived from sanitized object titles (lowercase, hyphenated, special characters removed). Handles name collisions by appending numbers (e.g.,
my-request
,my-request-2
). .gitignore
: Creates a.gitignore
file in collection directories to exclude draft files (~request.json
) from version control.
SettingsService
(src/main/persistence/service/settings-service.ts
):- Role: Manages application-wide settings that are not specific to a single collection.
- Storage: Settings are stored in a single JSON file:
USER_DATA_DIR/settings.json
.- The
USER_DATA_DIR
path is platform-dependent (e.g.,~/Library/Application Support/Trufos
on macOS,C:\Users\USERNAME\AppData\Roaming\Trufos
on Windows).
- The
- Key Settings:
currentCollectionIndex
: Index into thecollections
array.collections
: An array of directory paths to all known collections.
- Operations:
init()
: Loads settings from the file or creates default settings if the file doesn’t exist.settings
(getter): Provides read-only access to current settings.setSettings(settings)
: Updates settings and writes them to the file.modifiableSettings
(getter): Returns a deep clone of settings for modification.
- Default Collection Path:
USER_DATA_DIR/default-collection
.
Info File Format and Migration
- Info Files: JSON files (
collection.json
,folder.json
,request.json
) store the metadata for Trufos objects. - Versioning: Each info file contains a
version
field (e.g.,"version": "1.1.0"
), based onSemVer
(src/main/util/semver.ts
). - Latest Schema: Defined in
src/main/persistence/service/info-files/latest.ts
, which re-exports from the latest versioned file (e.g.,v1-1-0.ts
). - Migration (
src/main/persistence/service/info-files/migrators.ts
):- When an info file is loaded, its version is checked against the application’s latest supported schema version (
LATEST_VERSION
). - If the file’s version is older,
migrateInfoFile
is called. - This function iteratively applies migrators (defined in files like
v1-0-1.ts
,v1-1-0.ts
) to upgrade the info file schema step-by-step until it matches the latest version. - Each migrator (
AbstractInfoFileMigrator
) defines afromVersion
and amigrate
function. - Example changes in migrations:
v1.0.0
->v1.0.1
: Addedid
property (random UUID).v1.0.1
->v1.1.0
: Addedenvironments
property to collections.
- When an info file is loaded, its version is checked against the application’s latest supported schema version (
Request Body Storage
- Text Bodies:
- Stored in
request-body.txt
within the request’s directory. - Draft text bodies are stored in
~request-body.txt
. - The
RequestBodyType.TEXT
inrequest.json
indicates a text body.mimeType
is also stored.
- Stored in
- File Bodies:
- The
RequestBodyType.FILE
inrequest.json
indicates a file body. filePath
stores the absolute path to the user-selected file.mimeType
may also be stored.- Trufos does not copy the file into its own storage; it references the original file path.
- The
Data Integrity and Collaboration
- Storing data in separate files and directories, with metadata in JSON, makes collections relatively version-control friendly (e.g., with Git).
- The
.gitignore
helps avoid committing transient draft files. - The ID-based path mapping helps maintain references even if titles/directory names change, though moving files outside of Trufos could break these links.
This persistence strategy aims for a balance between human-readable/editable files, version control compatibility, and application performance.