Files
2026-08-19 17:18:45 +01:00

488 lines
23 KiB
Markdown

# joplin-cli-gateway
## Purpose
`joplin-cli-gateway` provides a stable, application-facing interface for using Joplin as a knowledge base from other software.
The gateway is backed by a managed Joplin CLI profile. It exposes authorised application operations over the functionality and local data model provided by Joplin CLI, so those applications do not need to install, configure, or directly automate Joplin themselves.
The project is intended primarily for personal use, providing a reusable integration layer so that multiple independent projects can use the same Joplin data without each project implementing its own Joplin integration.
Companion components may eventually include:
* an SDK for application integration;
* an AI skill for integration by AI-based projects and agents.
These components are outside the MVP and may evolve independently over time.
## Scope
The gateway exposes Joplin capabilities to authorised external clients.
Joplin concepts remain visible as Joplin concepts. The gateway does not introduce a generic knowledge-base abstraction over notebooks, notes, tags, resources, or other Joplin entities.
The gateway must remain independent of the purpose, domain, or behaviour of consuming applications.
## Shared Knowledge Base
Multiple independent client projects are expected to use the same Joplin data.
Each `joplin-cli-gateway` instance manages one dedicated Joplin CLI profile and provides authorised clients with access to the shared Joplin data represented by that profile.
In the MVP, one gateway deployment represents exactly one Joplin account, one dedicated CLI profile, and one shared knowledge base. Multi-account deployments and active-active gateway replicas are outside the MVP.
Joplin applications are offline-first clients: each keeps a local profile containing its data and synchronises that data with a sync target. Joplin Desktop and the gateway-managed Joplin CLI profile are separate peers of the same Joplin Server account.
Joplin Server is the existing central synchronisation service between the gateway-managed Joplin CLI profile and other Joplin clients. It continues to serve this normal Joplin role. This project does not recreate, replace, proxy, administer, or directly access the database of Joplin Server.
The gateway uses the Joplin CLI rather than Joplin Server as its integration layer because the CLI exposes capabilities and behaviour that Joplin Server does not directly provide as an application API.
The gateway invokes the CLI's normal synchronisation operation on an ongoing basis. This exchanges changes with Joplin Server, allowing applications using the gateway and humans using standard Joplin clients to work with the same knowledge base.
The gateway is the sole process permitted to access its managed CLI profile. It must serialise CLI/profile operations so two CLI processes never access that profile concurrently.
### Synchronisation Freshness
Freshness is prioritised over avoiding synchronisation work. The gateway must synchronise its managed CLI profile immediately before processing an application operation and immediately after any operation that changes Joplin content. It may additionally synchronise periodically while idle.
All synchronisation and CLI operations are serialised through the gateway's single managed profile. Thus a request observes changes that were available from Joplin Server at its pre-operation synchronisation point, and a successful content-changing request is synchronised to Joplin Server before the gateway reports it as complete.
In the MVP, a failed pre-operation synchronisation causes the associated operation to fail without reading or modifying Joplin content. The gateway must not answer a read from a potentially stale local profile when the required pre-operation synchronisation fails.
If a local mutation succeeds but its post-operation synchronisation fails, the gateway reports a degraded result: the operation succeeded in the gateway's local Joplin profile but has not yet been confirmed on Joplin Server. The response must distinguish this state from both complete success and complete failure. The gateway retains the local change and retries synchronisation periodically.
While such a change is pending, gateway clients share the same local profile and can therefore observe the same local state after a subsequent successful pre-operation synchronisation. Human Joplin clients cannot observe the change until it reaches Joplin Server, and may independently change the same content. A later sync can consequently produce normal Joplin conflict behaviour.
A separate post-MVP stale-read mode may allow the gateway to answer reads from its last known local state when the pre-operation synchronisation is unavailable. Any such response must explicitly warn the client that it may be stale. Stale reads remain outside the MVP.
### Transport and End-to-End Encryption
Communication between the gateway-managed CLI profile and Joplin Server must use HTTPS.
HTTPS protects data in transit. It is distinct from Joplin end-to-end encryption (E2EE), which encrypts synced Joplin items and requires the relevant Joplin client profile to hold and unlock its encryption keys.
Gateway-specific E2EE key handling is deferred beyond the MVP. External gateway clients never receive Joplin Server credentials or Joplin E2EE keys.
The same data is also accessed directly by humans through standard Joplin clients, including Joplin Desktop.
Content managed through the gateway remains ordinary Joplin content.
All clients are peers. They are considered different software representations of the same operator rather than independent owners of data.
Content has no client-level ownership.
A client with sufficient permissions may read, modify, move or delete content regardless of which client or human originally created it.
## Gateway Interface
The gateway exposes both REST and GraphQL interfaces. These are stable application APIs over the functionality provided by the managed Joplin CLI.
Clients interact only with the gateway API. They do not require a local Joplin installation, a Joplin CLI profile, Joplin Server credentials, or direct access to Joplin Server.
REST is the normative public contract. GraphQL exposes an equivalent projection over the same capability and authorisation model. Their exact schemas and compatibility rules are specified separately.
The proposed MVP surface and interaction semantics are documented in [`api-mvp.md`](api-mvp.md).
Programming language and framework options are evaluated in [`language-framework-analysis.md`](language-framework-analysis.md). The accepted implementation stack is TypeScript on Node.js with Fastify and Mercurius. Joplin remains isolated behind a replaceable adapter and a single-owner profile queue.
## Client Identity
Each client has a stable identity representing a project or application.
Client identity is not intended to represent:
* individual human users;
* individual sessions;
* individual requests.
Permissions and operational logging are associated with this stable client identity.
Clients authenticate to the gateway using OAuth-style access tokens associated with their stable identity. In the MVP, an operator manually creates each client identity, login credentials, and permissions in JSON configuration, then restarts the gateway container to apply the configuration.
The intended machine-to-machine interaction is a client-credentials token exchange. There are no human gateway logins, self-registration, or interactive authorisation flows in the MVP. Removing or disabling a client in configuration and restarting the container must cause every token for that client to be rejected on its next request.
## Access Model
The access-control model is **default deny**.
Anything not explicitly permitted is denied.
A client has no access or capability merely because it exists, authenticated successfully, created content previously, or has access to related content.
Permissions must support restrictions at notebook level together with independent global capabilities.
At minimum:
* full access;
* read-only access to specific notebooks;
* read/write access to specific notebooks;
* global notebook creation permission;
* global tag creation permission.
Global capabilities are independent of notebook permissions.
For example, a client may have read/write access to an existing notebook hierarchy without permission to create notebooks.
There is no note-level access control.
The permission model should remain deliberately small for the MVP.
### Permission Administration
Permissions are centrally administered.
Clients cannot modify their own identity or permissions in the MVP.
For the MVP, client identities and administrator-assigned permissions are maintained through manually managed configuration.
For the MVP, this configuration is stored in JSON. SQLite is the intended future persistence mechanism, without changing the client identity or permission model.
Administrator-owned configuration and gateway-generated state are separate. The administrator configuration is read-only to the gateway. Durable state created by gateway operations, including automatic grants for client-created top-level notebooks, is stored in a separate gateway-managed JSON state file in the MVP. Both are replaced by SQLite later without changing their semantics.
A future administration frontend may provide management of:
* clients;
* client identities;
* notebook permissions;
* global capabilities.
The API required by such an administration interface may later also be exposed to suitably authorised clients.
The permission model governing administrative operations is TBD and outside the MVP.
### Revocation
Permission revocation takes effect by removing the corresponding capability.
Revoked permissions confer no residual rights based on previous access, authorship, or modification of content.
If a client should retain read access while losing write access, its permissions are changed accordingly.
A fully revoked client has no further access.
### Visibility and Information Disclosure
A client must not be able to access the contents of notebooks for which it has no permission.
Unauthorised notebook contents behave as though they do not exist from that client's perspective.
This applies to:
* note retrieval;
* search;
* notebook contents;
* recent-change information.
Requests involving inaccessible objects should not disclose whether the object exists.
Authentication and authorisation behaviour should follow standard information-disclosure-minimisation practices.
A client may nevertheless be aware of otherwise inaccessible notebooks where necessary to represent the complete hierarchical path to a notebook it is authorised to access.
Knowledge of that path does not imply access to the parent notebook's contents.
### Notebook Hierarchy
Notebook access inherits downward through the Joplin notebook hierarchy in the MVP.
Access granted to a notebook includes its descendant notebooks.
A notebook subsequently created beneath an accessible notebook becomes visible and accessible to clients with access to that hierarchy.
Exceptions to inherited access are outside the MVP.
A client granted access directly to a descendant notebook may be shown the complete notebook path even when it has no content access to one or more ancestors.
### Read/Write Access
Read/write access includes normal note-management operations within the permitted notebook hierarchy:
* creating notes;
* editing notes;
* deleting notes;
* moving notes within the accessible hierarchy;
* applying and removing tags.
If a client has read/write access to multiple notebook trees, it may move notes between those trees.
There is no special ownership or source-tree restriction on such moves.
Further subdivision of note permissions is outside the MVP.
### Notebook Creation
Notebook creation is controlled by an independent global permission.
A client with this permission may create:
* top-level notebooks;
* descendant notebooks beneath accessible notebooks.
A client automatically gains access to a top-level notebook that it creates.
This automatic access is a durable read/write grant stored in gateway-managed state. It survives gateway restarts and remains until an administrator revokes it.
A descendant notebook follows normal hierarchy inheritance rules.
### Notebook Structural Changes
Operations that substantially restructure or remove notebooks are outside the MVP.
The MVP does **not** permit clients to:
* delete notebooks;
* move notebooks;
* rename or otherwise modify notebook properties.
These capabilities may be introduced post-MVP under a permissions model to be defined later.
### Deletion
Note deletion follows normal reversible Joplin behaviour.
The gateway does not introduce a separate destructive-operation permission for note deletion in the MVP.
Authorised clients may list and read trashed notes and restore a trashed note. Restoration follows normal Joplin behaviour by returning the note to its original notebook. The client must have write access to the restoration destination. If the original notebook no longer exists, the gateway rejects restoration with a conflict response; a human must resolve the destination in a standard Joplin client.
Permanent note deletion is outside the MVP.
## Tags
Tags are global.
All clients may:
* list existing tags;
* view tags;
* apply existing tags to notes they may modify;
* remove tags from notes they may modify.
Creating new tags requires a global tag-creation permission.
A tag may be visible even when some of the notes using it are inaccessible.
Tag operations must never expose inaccessible notes.
## Note Content
The MVP accepts and returns Markdown/plain-text note bodies. It does not accept images, attachments, binary resources, or HTML-specific input fields.
Clients may use normal Joplin Markdown content, including structures and links normally supported by Joplin.
The gateway must not introduce application-specific schemas, validation, or content conventions.
Joplin internal note links use the target note's native ID in Markdown. The gateway preserves these links as note content and does not rewrite them. Possessing an ID or encountering a link does not grant access to its target; any attempt to retrieve or resolve an inaccessible target behaves as though it does not exist.
Because the gateway does not reinterpret or redact authorised note bodies, text deliberately written into an accessible note—including a link label or target ID—is visible as part of that note's content.
To-dos are outside the MVP. Notes whose `is_todo` property is set may exist in Joplin, but they are hidden from MVP clients and excluded from listing, retrieval, search, recent changes, trash, and note-history results.
Joplin conflict notes are hidden from MVP clients and excluded from listing, retrieval, search, and recent-change results. Conflict inspection and resolution are outside the MVP.
The exact safe set of client-writable note metadata beyond notebook, title, and body is TBD.
## Trash and Note History
The MVP exposes authorised access to trashed notes and normal Joplin note history.
Clients with read access to a note's notebook may inspect its available historical versions. Restoring a historical version follows Joplin's normal non-destructive behaviour: it creates a new restored note rather than overwriting the current note.
Restoring a trashed note or historical version requires write access to the destination notebook. When restoring a historical version, the client must explicitly select an existing writable destination notebook. The restored version is created there as a new note and does not overwrite the current note. The gateway does not promise that a particular historical version exists; availability and retention follow the Joplin revision service and its configured retention behaviour.
Clients cannot create, edit, or delete raw revision records directly.
## Search
Search operates only over content visible to the requesting client.
Inaccessible content must not:
* appear in results;
* expose its contents;
* contribute inaccessible result information.
## Identifiers
Native Joplin identifiers may be exposed directly to clients.
The gateway does not require a separate identifier namespace or attempt to hide Joplin object identity.
Client applications may use Joplin IDs as canonical references where appropriate.
## Metadata and Logging
Normal Joplin metadata is sufficient for content provenance.
The gateway does not add client identity, ownership, or gateway-specific provenance to Joplin content.
Operational logging should identify the client responsible for gateway operations for debugging and troubleshooting purposes.
## Concurrent Access
Multiple software clients and human Joplin users may concurrently modify the shared knowledge base.
The gateway exposes existing capabilities that allow authorised clients to inspect recent changes across content visible to them.
Use of this capability is optional.
Clients remain responsible for deciding whether checking for recent changes is appropriate before modifying content.
An MVP write may optionally include the note's expected `updated_time`. If the current note has a different value after the mandatory pre-operation sync, the gateway rejects the write as a conflict instead of overwriting it. Omitting this guard accepts normal Joplin last-write/conflict behaviour.
Documentation should encourage clients to inspect recent changes before making modifications where concurrent activity may matter.
The gateway does not provide application-level merge semantics or automatic conflict resolution.
## Functional Scope
### MVP
The MVP focuses on:
* stable client identities;
* default-deny access control;
* centrally administered permissions;
* notebook-level read and read/write permissions;
* independent global notebook creation permission;
* independent global tag creation permission;
* create notes;
* read notes;
* edit notes;
* delete notes;
* list, read and restore trashed notes;
* inspect available note history and restore a historical version as a new note;
* list and navigate permitted notebooks;
* create top-level or descendant notebooks where permitted;
* move notes between authorised notebook trees;
* list and use tags;
* create tags where permitted;
* search permitted content;
* expose existing recent-change information within permitted content;
* expose normal Joplin metadata and identifiers;
* operational logging identifying the responsible client.
### Post-MVP
Explicitly deferred:
* attachments and resources;
* to-do-specific operations;
* notebook deletion;
* notebook movement;
* notebook renaming and other property changes;
* exceptions to inherited notebook permissions;
* finer-grained structural permissions;
* administrative API;
* administrative frontend;
* client-accessible permission management;
* SDK;
* AI skill;
* broader Joplin feature coverage.
### Post-MVP Realtime Events and Subscriptions
Clients may maintain persistent WebSocket connections to receive updates after they occur.
Clients may create subscriptions filtered by one or more conditions, including:
* change type, such as note creation or modification;
* one or more authorised notebook hierarchies;
* tag membership;
* keywords or other supported note-search conditions;
* combinations of these conditions.
Realtime delivery must be based on a transport-independent event stream rather than treating a WebSocket connection as the event history. A disconnected client must be able to resume from a cursor and reconcile from the normal API if its cursor is no longer valid.
Events and subscription matches are evaluated only after applying the subscriber's current permissions. Revocation must stop further delivery and close or invalidate affected persistent connections. Events must not disclose inaccessible objects, counts, filter matches, or previous values.
The future subscription model must distinguish an object event from a match transition. For example, “a note was created while matching this filter” differs from “an existing note began matching because its text or tags changed.” Exact subscription and delivery guarantees are TBD post-MVP.
These future requirements influence the MVP only by requiring stable event identifiers, resumable cursors, a versioned event envelope, and separation between event semantics and delivery transport. WebSockets, saved subscriptions, and guaranteed delivery are not part of the MVP.
## MVP Acceptance Criteria
The MVP must demonstrate that:
* a note created in Joplin Desktop becomes readable by an authorised gateway client after synchronisation;
* a note created through the gateway becomes visible in Joplin Desktop after synchronisation;
* an unauthorised client cannot infer that an inaccessible note exists;
* client revocation takes effect on the next request after configuration is applied by container restart;
* failure of the required pre-operation sync prevents stale reads;
* no two processes can concurrently access and corrupt the gateway-managed CLI profile;
* search and recent changes do not leak inaccessible content;
* the only exception to notebook non-disclosure is the minimum ancestor path needed to represent an authorised nested notebook.
## Design Principles
### Joplin Remains Joplin
The gateway exposes Joplin's own concepts, identifiers, content and behaviour.
### Human and Software Coexistence
Humans using standard Joplin applications and software using the gateway operate on the same knowledge base.
Neither mode of access should make the data unsuitable for the other.
### Peer Clients
Clients do not own content.
Any authorised client may operate on any content within its permitted notebook hierarchy regardless of origin.
### Stable Client Identity
Projects and applications are persistent actors with stable identities and permissions.
### Default Deny
No access or capability exists unless explicitly granted.
### Central Authority
Clients operate only within permissions granted externally to them.
A client cannot expand its own authority.
### No Note-Level ACL
Access control applies to notebook hierarchies and global capabilities, not individual notes.
### Independent Capabilities
Notebook access and global operations such as notebook or tag creation are independently authorised.
### Minimal Information Disclosure
Unauthorised access must not reveal unnecessary information about inaccessible objects.
### Client-Project Agnostic
The gateway must make no assumptions about a client's domain, workflow, semantics or purpose.
### Minimal Policy
The gateway enforces permissions but otherwise avoids imposing application-specific policy.
### Shared Use
Multiple independent projects may use and modify the same Joplin knowledge base according to their permissions.
### Client-Managed Concurrency
The gateway exposes available state and change information but does not require clients to use it.
Clients remain responsible for avoiding unintended conflicting changes.
### Simple Permissions First
The MVP uses a deliberately coarse permission model.
Additional granularity should only be introduced when actual use cases justify it.
### Progressive Coverage
The MVP provides the minimum useful knowledge-base functionality.
Additional Joplin capabilities may be progressively exposed without changing the gateway into an application-specific service.