|
Some checks are pending
Build and push Joplock image / build-and-push (push) Waiting to run
- TinyMCE Enter at end of a non-empty checkbox now always inserts a new checkbox item, regardless of what follows (paragraph, another checkbox, or nothing). Exiting the list is done via Enter on an empty item. This fixes being unable to add items to an existing checklist that is followed by other text; only bottom-of-note appends worked before. - Restore rendered-mode title auto-fill broken by ffb7bd0: onEdit now calls a cheap DOM-only autoTitleFromTinyMCE() instead of relying on a per-edit synthetic textarea 'input' event. - Tests: rewrite checkbox-enter-behavior.spec.js (end-of-note, followed-by-text, empty-item exit); remove checkbox-exit.spec.js (encoded old exit-on-following-paragraph behavior); add autotitle-rendered.spec.js and tinymceOnEditSync auto-title guards. |
||
|---|---|---|
| .github/workflows | ||
| app | ||
| cm-build | ||
| hljs-build | ||
| playwright-tests | ||
| public | ||
| scripts | ||
| tests | ||
| vendor/turndown-lib | ||
| .dockerignore | ||
| .gitignore | ||
| AGENT_GUIDE.md | ||
| AGENTS.md | ||
| docker-compose.example-full-build.yml | ||
| docker-compose.example-full.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.js | ||
| README.md | ||
| server.js | ||
Joplock
A secure, fast web client for Joplin Server.
Joplock runs as a sidecar alongside an unmodified Joplin Server instance, sharing the same Postgres database, sessions, notes, folders, and resources. It gives you a lightweight browser-based interface to your Joplin notes without modifying Joplin Server itself. Keep using the other Joplin clients too, this won't interfere.
Key Features
- Full Joplin compatibility -- desktop, mobile, CLI, and Joplock all work with the same account and data simultaneously
- Low Resource usage -- minimal memory usage on the client, fast and responsive
- Security-first design -- no private data stored on the client; sessions are cleaned up on logout; per-user settings and admin controls for user management
- Client-side encrypted vaults -- turn any notebook into a vault; notes inside are AES-GCM encrypted in the browser with a PBKDF2-derived key. The server never sees vault passwords. Ciphertext is bound to a specific vault and note id, and the server rejects any write that would land a vault-encrypted body in the wrong note or the wrong vault
- Dual-mode editor -- CodeMirror 6 for markdown editing and TinyMCE 8 for rich rendered mode, switchable per note; mobile opens in a read-only rendered view with an edit toggle
- Tables, code blocks, and lightbox -- full-screen code editor modal with language picker, TinyMCE tables with markdown round-trip, and a lightbox for images and attachments
- Note export -- export any note as Markdown, single-file HTML (images and links inlined), DOCX (server-side via pandoc with reference styles), or PDF, with visible table gridlines in PDF/DOCX output
- AI autocomplete -- optional prose completion via user-configured provider profiles (OpenRouter and others), triggered by Ctrl/Cmd-Space or configurable Expander triggers; per-user text expanders for snippets
- Concurrent-edit detection -- detects when another client (or another browser tab) has updated the same note and offers Overwrite / Create copy so edits are never silently lost
- Multiple themes -- Grey, Fruit, Dark Fruit, Earth, Swamp Thing, Fireball, and more, all as CSS custom-property sets; per-user theme picker in the status bar and settings page
- User creation from Joplock UI -- create and modify users directly from Joplock settings page
- Full database backup and restore -- create and restore complete Postgres backups for both Joplin and Joplock data
- Multi-factor authentication -- optional TOTP-based MFA on top of standard Joplin sessions
- Fast search -- searches titles and note bodies directly in Postgres; optional live-as-you-type search
- Near-instant autosave -- debounced saves with conflict detection, hash-based deduplication, and an undo ring buffer with full note history snapshots. Restoring a snapshot updates the open editor immediately without a page refresh
- PWA support -- installable as a home screen app on mobile and desktop with splash screens, offline indicator, and service worker shell
- Server-side rendering -- SSR with htmx for minimal client-side JavaScript
Runtime Model
Joplock:
- reads Joplin data directly from the shared Postgres database
- validates the same
sessionIdcookie used by Joplin Server - writes notes, folders, and resources through stock Joplin Server APIs
That keeps desktop, mobile, CLI, and Joplock compatible with the same account and data.
Requirements
- docker
- an existng Joplin Server instance, or run the fullstack option
Environment
All configuration is done directly in the compose files via inline environment variables with comments. No .env file is needed -- just edit the values in docker-compose.yml or docker-compose.example-full.yml before starting.
Backup and recovery configuration:
JOPLOCK_BACKUP_DIRenables server-side full database backupsJOPLOCK_BACKUP_COMPRESSIONcontrols thepg_dumpcompression method, for examplezstd:19orgzip:9JOPLOCK_BACKUP_COMPRESSION_LEVEL=0-9controlspg_dumpcompression for backup filesJOPLOCK_RECOVERY_ENABLED=trueenables the break-glass recovery page at/recoveryJOPLOCK_RECOVERY_PASSWORDprotects that recovery page
Important:
- Backups are only durable if
JOPLOCK_BACKUP_DIRis mounted to persistent storage. - Default backup compression is
zstd:19, which is usually smaller thangzip:9. JOPLOCK_BACKUP_COMPRESSIONtakes precedence overJOPLOCK_BACKUP_COMPRESSION_LEVEL.- Higher compression produces smaller backup files but may take longer to create.
- Recovery mode is for backup and restore only, not regular note usage.
- Restore replaces the entire shared Postgres database, including Joplock-owned tables.
Docker
Published container image:
ghcr.io/abort-retry-ignore/joplock:latest
Sidecar Install
Use this when you already have Joplin Server and Postgres running elsewhere. Edit the environment values in docker-compose.yml to point at your existing setup, or copy into your existing compose. Then:
docker compose up -d
This pulls the pre-built image from GitHub Container Registry. To build from source instead:
docker compose -f docker-compose-build.yml up -d --build
On Linux, the compose files map host.docker.internal to the host gateway so Joplock can reach host services by default.
Backup And Restore
Normal workflow:
- Sign in as the configured Joplock admin.
- Open
Settings -> Admin -> Backup & Restore. - Create a backup or restore an existing server-side backup.
Break-glass workflow when normal Joplin login is unavailable:
- Enable
JOPLOCK_RECOVERY_ENABLED=trueand setJOPLOCK_RECOVERY_PASSWORD. - Open
/recovery. - Sign in with the recovery password.
- Create or restore full database backups from there.
Before restoring:
- Stop or quiesce Joplin Server if possible.
- Stop active sync clients.
- Expect the entire shared Postgres database to be replaced.
Full Example Stack
Use this as a reference/demo stack with Postgres, Joplin Server, and Joplock together. Edit the values in docker-compose.example-full.yml as needed, then:
docker compose -f docker-compose.example-full.yml up -d
The full example uses the public joplin/server:latest image. Joplock is exposed on http://localhost:5444 by default. Joplin Server is internal-only unless you add a port mapping.
The full example is meant as a working reference compose file. Adjust it for your real deployment.