v1.8 is the first feature release since Meerkat moved to the meerkatcrm organization. It adds contact merging, employment history, a Simplified Chinese translation and per-circle CardDAV sync. It also fixes a long-standing bug that stopped recurring reminders, including birthday reminders, after you completed them once, and it closes several security gaps.
! Before you upgrade !
- The image path has changed. Images are now published at
ghcr.io/meerkatcrm/*. If your compose file still points toghcr.io/fbuchner/*, you will not get this release. Update theimage:lines, or download the currentdocker-compose.yml, then rundocker compose pull && docker compose up -d. - Back up your database. Ten migrations (24 to 33) run automatically at startup. Migration 31 rebuilds the
userstable, and migration 32 changes reminder data (see below). - Everyone signs in once more. Sessions created before the upgrade can't be renewed and end at their current expiry.
- New setting
JWT_MAX_SESSION_HOURS(default 720, orJWT_EXPIRY_HOURSif that is larger).JWT_EXPIRY_HOURSnow means the maximum idle time, because sessions renew while you use them.JWT_MAX_SESSION_HOURSis the hard limit from sign-in. It must be betweenJWT_EXPIRY_HOURSand 8760. FRONTEND_URL=*together with OIDC is now a startup error. SetFRONTEND_URLto your real address when using OIDC.- Tailscale and other CGNAT addresses (
100.64.0.0/10) are now treated as private. If you turned onWEBHOOK_BLOCK_PRIVATE_URLS,MONICA_BLOCK_PRIVATE_URLSorCALDAV_BLOCK_PRIVATE_URLS, targets on those addresses stop working. While the webhook guard is on, webhooks also no longer go throughHTTP_PROXY/HTTPS_PROXY.
New features
- Find and merge duplicate contacts. Under Contacts → Find duplicates, Meerkat lists pairs that share a name, an email address or a phone number. You can merge two contacts and pick which value to keep wherever they differ. Notes, activities, reminders and relationships move to the contact you keep. (#276)
- Employment history. A new tab lists past and current jobs with partial dates. Organization, department, job title and role now come from the current job. (#278, #294, #302)
- Simplified Chinese (zh) translation. (#271, #275)
- Choose which circles sync to your phone. The built-in CardDAV server can sync all contacts, only the contacts in chosen circles, or all except those circles. Set it under Settings → Data. (#274)
- Deceased contacts. You can mark a contact as deceased. Deceased contacts are left out of birthday reminders. (#222)
- Turn birthday reminders on and off from the contact page. The reminder follows birthday changes. Known-issue: birthdays on 29th Feb will be reminded 28th Feb in the year after and then reminders stay on 28th Feb. (#227)
- Export a single contact as a vCard. Single and bulk exports both let you choose vCard 3.0 or 4.0. (#224)
- Hide empty contact fields. This is optional and off by default, you can change it in the settings. A button shows the empty fields when you want to fill them in. (#272)
- Stay signed in while you use the app. Active users are no longer logged out every
JWT_EXPIRY_HOURS. (#280) - Collapsible sidebar. The sidebar is wider and can collapse to icons. (#221)
Improvements
- Faster first load: pages now load on demand, which roughly halves the initial download. The frontend now builds with Vite instead of Create React App. (#288)
- Dates in the activity, timeline and network dialogs now use your preferred date format. (#302, #233, #307)
- The contact field settings have new defaults (#302)
- Layouts work on phones and at high zoom. Pages no longer scroll sideways, and buttons no longer clip their labels. (#304, #305)
- The Monica import keeps children who aren't separate contacts, with their birthdays. The report now lists each skipped item. (#269, #218)
- Confirmation dialogs are now consistent across the app. Failed saves on the notes, activities, network and dashboard pages show an error. (#307)
- The CSV export includes the newer contact fields. (#307)
Fixes
Reminders
- Recurring reminders on a fixed schedule stopped after you completed them once. This affected every birthday reminder since v0.6.0. Migration 32 brings them back at their next date, so no overdue emails go out. (#292)
- Birthday reminders are stored as calendar dates. In time zones east of UTC+10 they were saved a day early, and in time zones west of UTC the toggle could create duplicates. Changing a birthday now moves its reminder. (#303)
- Startup no longer loses the reminder, calendar sync or CardDAV sync run because of a locked database. Running the daily job twice on the same day no longer sends duplicate emails or webhooks. (#299, #307)
Sync and import
- Contact sync works with servers that send unquoted ETags, such as Mailbox.org. (#259)
- vCard 2.1 imports keep phone numbers, emails and other fields. (#251)
- Importing a vCard again restores a contact you had deleted, instead of failing. (#223)
- Deleting a contact from a phone or through sync now also removes its notes, reminders, relationships and employment history. A value you remove on your phone no longer comes back. (#307)
- Concurrent contact merges no longer fail with a server error. (#299)
Other
- Webhooks, calendars and CardDAV connections that you create inactive now stay inactive. (#292)
- Several OIDC accounts without an email address can now exist side by side. (#292)
- Search treats
%and_as ordinary characters. (#270) - Your language and date format apply right after you sign in. (#307)
- The
.envexample now documentsPORTinstead of the unusedHOST_PORT. (#220)
Security
- Webhook SSRF protection now checks the address at connection time, which also covers DNS rebinding and redirects. More reserved IP ranges count as private for webhooks, sync, Monica and image fetching. (#283, #292)
- A deleted user's API tokens and sessions stop working right away. Their stored credentials are deleted, and their scheduled syncs and webhook retries stop. Deleting a user now removes the account, which frees the username and email. (#283, #284, #292)
- Login and password reset no longer reveal which accounts exist. Each account gets at most one reset email per minute. (#283)
- Stored CardDAV and calendar passwords are cleared when the server address changes. A reminder can no longer be attached to another user's contact. (#292)
- Sessions signed in before a password change are not renewed. (#280)
- URL ids are validated and bound as query values. Error responses no longer include panic details. Images larger than 64 megapixels are rejected before they are decoded. (#306, #307)
- The frontend now has no known vulnerabilities in production dependencies, down from 41. (#288)
For API and integration users
- Auth, rate-limit and admin errors now use the standard envelope
{"error": {"code", "message"}}instead of{"error": "text"}. (#307) - A non-numeric id in a
/api/v1path returns400instead of404. (#306) - On
PUT /contacts/:id,organization,department,job_titleandroleupdate the current employment entry. Blank fields keep their stored value. Use the employment history endpoints to clear a field or end a job. (#294) - A CardDAV update that leaves out a phone number, email, address, URL, nickname or birthday now removes it. (#307)
- Password reset always returns
200. Mail failures appear only in the server log. (#283) - API tokens can now call the language, date format and change-password endpoints. (#306)
Known limitations
- Birthday reminders that an older version saved a day early (UTC+10 and east) are not corrected automatically. They still go out a day early, and the toggle shows them as off. To fix one, delete the old reminder and turn the toggle on again.
- If you never saved your contact field selection and have Work Information on a contact, migration 33 keeps your previous field set. Newly added fields such as Websites stay off until you turn them on in Settings → Contact Fields.
Thanks
Thanks to @ymage for employment history, deceased contacts, vCard export, birthday reminder toggles, the collapsible sidebar and sliding sessions. Thanks to @omarkohl for the first contributions: the vCard 2.1 and Mailbox.org sync fixes, linting in CI and a Docker-free development setup.
Full Changelog: v1.7.0...v1.8.0
Docker Images
All-in-one image (frontend + backend in one container):
ghcr.io/meerkatcrm/meerkat-crm:1.8.0
Separate images:
ghcr.io/meerkatcrm/meerkat-crm-backend:1.8.0
ghcr.io/meerkatcrm/meerkat-crm-frontend:1.8.0