# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [1.10.3] - 2026-07-28, Berlin ### Added - The Map v2 "Edit points" toggle is now remembered between sessions instead of resetting to off on every page load; it still defaults to off, so points stay protected from accidental drags until you opt in. On the Lite plan it stays session-only, since editing points requires Pro. (#3085) ### Changed - The Docker image no longer ships ImageMagick — nothing in the app used it, so the image gets smaller. (#3139) ### Fixed - Turning "Edit points" off on Map v2 now reliably disables point dragging. Changing the map style while editing was on left a stale drag handler attached, so points stayed draggable no matter what the toggle said. - The Family entry in the navigation bar is now clickable across its entire button area instead of only the label text. (#3100) - The Dawarich app and Sidekiq containers now restart automatically after a graceful (exit 0) shutdown instead of staying down, so a stray SIGHUP no longer takes an instance offline until manual intervention (#3099). - Nightly place- and area-visit calculation no longer fails when an instance contains legacy points without timestamps. - Import rows on the Imports page now update their status live as an import processes, instead of staying on "Processing" until the page is manually reloaded. (#3174) - Public live-share links now update in real time for signed-in visitors, instead of only refreshing the location on a full page reload. (#3111) - Reverse geocoding and place-name provider outages no longer flood error reporting with handled timeouts, dropped TLS connections, refused connections, unresolvable hostnames, or invalid provider responses. A misconfigured or rate-limited provider — a bad API key, for example — is still reported. - The place search box behind visit naming and the Map v2 place picker gets the same treatment: a query the geocoder rejects, or a provider that is briefly unreachable, is logged and returns no matches instead of raising an application error. Self-hosted logs now name the failing error class, and a misconfigured or rate-limited provider is still reported. - Unexpected place search errors no longer include the search query or coordinates in error reports. - Place visit detection no longer fails when an unused suggested place is deleted while the nightly calculation is running. - Clicking "Continue reverse geocoding" again now re-processes points that were left ungeocoded by a previous run, instead of skipping them for up to a day. (#3071) - Public share links now expire at the start of the selected date in the owner's timezone instead of remaining active through that day (#3112). - The share link form now spells out that a link stays active only through the day before the selected expiry date. ## [1.10.2] - 2026-07-27, Berlin ### Added - Poster Studio has a track width control: a 50–300% slider beside track opacity that scales the route line on the saved poster. - The Map v2 custom basemap field now accepts raster XYZ tiles (`.png`/`.jpg`/`.jpeg`/`.webp`) and full MapLibre style URLs ending in `.json`, in addition to Protomaps-schema vector tiles. Previously a raster URL rendered as a blank grey map and a style URL was rejected. (#3146) ### Fixed - Saving a zoomed-out Poster Studio view to the gallery no longer rejects routes that are visibly inside the poster frame (#3204). The area check now uses the same Mercator framing as the renderer and wraps across the antimeridian, so high-latitude and Pacific-centred posters are judged against the frame you actually see. Poster Studio also warns when a view is too wide for the largest poster area instead of silently zooming the saved poster in. - Instances with heavy write traffic no longer crash-loop on the 1.10.1 upgrade. Dropping the legacy `points.latitude`/`points.longitude` columns needs an exclusive lock that busy instances could not win in one attempt, which aborted the migration and restarted the container in a loop. The drop is now retried, and if it still cannot get the lock it is handed to a background job so startup completes. If that job cannot get the lock either, the columns stay and the log prints the statement to run by hand — they are unused, so nothing breaks in the meantime (#3176) - Trial lifecycle email jobs left over from older releases are now discarded instead of retrying forever in the background queue. Mail addressed to a record that has since been deleted is also discarded rather than retried. - Reverse geocoding and place-name provider outages no longer flood error reporting with handled timeouts, dropped TLS connections, or invalid provider responses. A misconfigured or rate-limited provider — a bad API key, for example — is still reported. - Reverse geocoding retries point updates that time out while waiting on concurrent writes. - Google Semantic History and phone Timeline imports now tag points with a per-import tracker id instead of one shared constant, so tracks from different devices are no longer braided together. A one-time backfill rewrites existing points and regenerates affected tracks per user. - Place names you set yourself are no longer overwritten by nightly reverse geocoding. Renaming a place, creating one by hand, or picking one on the timeline locks its name; renaming it back to "Suggested place" hands it back to auto-naming. Map v2 and the place drawer show when a name is locked. A one-time backfill locks names that were customised before this release (#3086, #3175) - Real-time visit detection no longer stops after the first run for users who track continuously — the debounce key is now released when the job runs. - The nightly visit suggestion job no longer scans forward to the end of the calendar year; it processes only the day it was asked for. - Merged visits now report the correct duration, centre, radius and suggested name instead of keeping the values of the first cluster in the merge. - Visit suggestion failures no longer show a raw stack trace in your notifications, and repeated failures within an hour no longer create a notification each time (#3091) - Points at exactly (0,0) — a common GPS glitch — are no longer accepted from any ingestion path (API, OwnTracks, Overland, Traccar, file imports) and no longer produce suggested visits at "Null Island". Existing (0,0) points are flagged as anomalies by a one-time cleanup that also removes visits placed at (0,0), tolerates legacy points without timestamps, and recalculates affected stats and tracks. - Point uploads from all ingestion paths (REST API, OwnTracks, Overland, Traccar) now retry transient statement and lock-wait timeouts, not just deadlocks, instead of failing the upload. - The DNS caching layer no longer crashes with a misleading `NoMethodError` when the SMTP server is not configured in the background worker, so email delivery surfaces the real configuration error instead. (#3038) ## [1.10.1] - 2026-07-19, Berlin ### Added - Google Photos Takeout metadata sidecars can now add geotagged photos as sparse timeline points; sidecars without usable coordinates are skipped. - The Poster Studio can now be opened directly from a trip's page, pre-loaded with the trip's route, date range, and name. - Dawarich can now be installed to the phone home screen as a web app (PWA): all pages link the web app manifest and Apple touch icon, and the installed app opens straight into Map v2. ### Changed - The legacy `latitude`/`longitude` columns on `points` are dropped — the PostGIS `lonlat` column has been the single source of truth since 0.25.0. The migration copies any remaining legacy-only coordinates into `lonlat` before dropping, so upgrades from older versions are safe. - File imports no longer store a copy of each source record in the point's `raw_data` — the uploaded file stays attached to the import as the source of truth. API responses return `raw_data: {}` for newly imported points, and FIT/TCX health fields (heart rate, cadence, power, temperature) as well as Google phone takeout HOME/WORK place labels are no longer stored. - TCX and FIT imports now store their activity type in `motion_data`: transportation-mode detection works for TCX imports for the first time, and FIT driving activities are classified correctly. - Google phone takeout imports now store the mapped activity type in `motion_data`, so transportation-mode detection (driving, walking, cycling, bus, train, flying) works for activity segments from phone takeout files. ### Fixed - Deleting a single point from the map now recalculates your monthly distance and statistics, instead of leaving them counting the deleted point. - Large GeoJSON imports now stream features in bounded batches instead of loading the entire file into memory, preventing worker memory exhaustion on exports with hundreds of thousands of points. - Google phone Timeline imports now stream semantic segments and raw signals in bounded batches instead of loading the entire export into memory, preventing worker memory exhaustion on large Timeline files. - FIT activities without a `device_info` section now import their location records instead of failing strict FIT validation. - GPX imports now preserve XML byte-order marks, allowing files whose BOM correctly identifies the encoding despite an incorrect XML declaration to import successfully. - ZIP imports now accept large activity exports containing up to 25,000 files, while retaining file-count and expanded-size safety checks. - OwnTracks `_type: waypoint` sync messages are no longer stored as location points, so syncing your saved OwnTracks places no longer creates phantom distance/track spikes (#3137) - Map v2 date pickers now keep the time component when a range with a specific time is loaded from the URL, instead of resetting to the start/end of the day (#3106) - Track generation and user data recalculations now retry a bounded number of times when another job is already processing the same user's tracks, instead of dropping the request and reporting an error; a genuinely stuck lock is logged after the retries are exhausted. The per-user lock also renews itself while a job runs and frees within a minute if a worker dies, so a crashed job no longer blocks a user's track processing for up to half an hour. - Dawarich added to an iOS Home Screen now opens Map v2 instead of an unrelated previously visited page (#3097) - Point uploads (REST API, OwnTracks, Overland, Traccar) now write batches in a consistent order so concurrent uploads no longer deadlock each other, and both uploads and anomaly filtering recover automatically from any remaining transient database deadlocks instead of failing the upload or background job. - Reverse geocoding overlapping places no longer exhausts retries because of concurrent database deadlocks. - The app and Sidekiq containers no longer crash-loop on startup when `WEB_CONCURRENCY` or `BACKGROUND_PROCESSING_CONCURRENCY` reach the container as an unexpanded `${VAR:-default}` string (seen with some podman-compose versions); the entrypoint now warns and falls back to the default value (#3124) - Cache preheating no longer times out for accounts with large location histories. - Cloud: Changing plans resets the Lite archival-warning state, so a user downgraded to Lite again is notified about archived data again. - TCX and KML imports no longer fail when text fields contain raw ampersands. - The Map v2 "Share" button no longer renders its label below the button bounds on narrow layouts (#3007) - Outgoing email now works with local unauthenticated SMTP relays: set `SMTP_AUTHENTICATION=none` (also `off`/`false`/`disabled`) to disable SMTP AUTH instead of hitting "SMTP-AUTH requested but missing user name" (#3147, #2690, #1469, #1463) - Deleting a place from the Places list no longer jumps back to the first page — you stay on the page you were viewing (#3145) - Map v2 now applies the existing simplified point-rendering mode, so dense point streams are thinned on the map when that setting is selected. Only the points layer is thinned — heatmap, fog of war, scratch map, and routes are still built from the full point set (#946). - Statistics pages no longer fail to load when older monthly data contains malformed country or city entries. Recalculating stats for an affected month repairs the stored data. ## [1.10.0] - 2026-07-15, Malmö ⚠️ Important: ⚠️ there are some changes to defaults in the docker-compose.yml for self-hosted users. You may want to adjust environment variables to reduce memory usage or increase concurrency. See the "Changed" section below. ### Added - Poster Studio: design a printable poster of your travels in a full-screen studio opened from Map v2, with live preview, theme and layout presets, text controls, and PNG/PDF export. Posters can be saved to a server-rendered gallery or — in the future releases — ordered as a print via Stripe. Self-hosters: the Docker image grows by ~100 MB for the server-side renderer, and gallery rendering is unavailable on 32-bit ARM (armv7) hosts. - New API endpoints `GET`/`POST`/`DELETE /api/v1/demo_data` to check, load and remove demo data, enabling demo-data onboarding in the mobile app. - New API endpoints `GET`/`PATCH /api/v1/settings/mobile` for syncing mobile app settings between devices (most recent write wins). The existing settings API now also accepts `maps.distance_unit` and merges the `maps` hash instead of replacing it, so partial updates no longer wipe other map settings. - Map v2 now reopens at your last viewport instead of the zoomed-out globe when the selected date range has no data to fit. - Custom map colors: pick from theme presets or edit individual color tokens for the map, and a reorganized, collapsible Settings tab to manage them. - The classic map (v1) now shows a dismissible banner announcing its retirement in August 2026, plus — when your family shares location — a second banner noting that family location history is only visible on Map v2. Dismissals are remembered per browser. ### Changed - The default self-hosted stack now idles about 20% lighter (app container 452 → 325 MB, whole stack 843 → 690 MB): `docker-compose.yml` defaults to one Puma worker (`WEB_CONCURRENCY=1`) and 3 background job threads (`BACKGROUND_PROCESSING_CONCURRENCY=3`) — raise either env var for busier instances — and jemalloc now returns freed memory to the OS promptly. Installations that already set these variables are unaffected (#3119). - Deleting a point on Map v2 now removes it instantly and restores it if the delete request fails. - During replay, photos now stack up as a tilted, Polaroid-style pile in the top-left corner as the playhead reaches them (newest on top, up to five shown); click a photo to open it. The pile stays in sync as you play, scrub, or rewind, and works on map, trip, and public shared-trip replays. - Toggling the photos layer during a running replay now adds or removes its photos live (corner pile and map markers) — previously photos only appeared if the layer was enabled before starting the replay. - Replay panel: a new **recenter & follow** button. The camera follows the moving marker during playback; dragging the map turns following off, and the button re-centers and resumes it. - The replay panel no longer shows the per-day point count. - `GET /api/v1/points` is significantly faster over large date ranges: slim responses are built from a single SQL query (~5× faster, byte-identical output), the bounding-box filter runs as a single PostGIS predicate, and repeat requests answer `304 Not Modified` via ETags. Map v2 and the monthly stats map both use this path (#3026). - Public shared-trip pages now query Immich/Photoprism once per view instead of twice: the photo search result is briefly cached and reused. ### Fixed - Family location history now actually shows up on Map v2: the history endpoint read coordinates from the legacy `latitude`/`longitude` columns, which are empty on instances that only store the PostGIS `lonlat` value, so nothing was drawn. Coordinates are now derived from `lonlat` (#2977) - Declining the "Move the visit here?" prompt when picking a distant place for a Map v2 visit no longer renames the visit to that place. - Place visit detection no longer leaves an empty duplicate visit behind when a new point bridges two previously separate visits at the same place — they are now merged into one. The nightly re-scan also leaves confirmed visits untouched, so a new nearby point can no longer pull points out of a visit you already confirmed. - Re-evaluating anomalous points now refreshes the map immediately instead of occasionally serving a cached copy of the points until the next change. - Raw data archival: reading archived `raw_data` back works again (it silently returned nothing before), archive chunks are labeled with the points' actual month, archives are verified at write time, and the previously broken `points:raw_data:archive`/`archive_full` rake tasks work again. - Raw data archival, continued: re-importing a duplicate point with different `raw_data` now detaches it from its stale archive so the newer data can't be cleared away, and clearing archived data now waits out a 7-day cooling window. Restores are reported under the `restored` metric label instead of `removed` — update dashboards reading `points_total{operation="removed"}` accordingly. - User data exports now include archived `raw_data` as plain gzip files, so an export can be imported on a different instance (previously the archives were encrypted with the exporting instance's key and unreadable elsewhere). - Creating, updating, or deleting a user in Settings no longer shows a blank "HTTP ERROR 422" page when validation fails — the admin is redirected back with a message explaining what went wrong (e.g. password too short) (#3051) - Email delivery no longer times out with providers that use implicit TLS (SMTP port 465, e.g. many hosted mail services): set `SMTP_SSL=true` to enable it, and it is enabled automatically when `SMTP_PORT=465`. STARTTLS remains the default for all other ports (#3068) - Points on Map v2 can no longer be moved by accident: dragging a point now requires enabling the new "Edit points" toggle in the layers panel. The toggle resets on every page load, so points stay put unless you deliberately turn editing on (#3060) - The family "Location history" toggle is clearer: the settings page now explains it is distinct from live location, powers the recent-track view on Map v2, and only shares points recorded after enabling it. The default history window grew from 24 hours to 7 days, so newly-shared members show a useful track. - Place-based visit suggestions now work for users whose distance unit is kilometres — an integer-rounding bug set the detection radius to zero. Self-hosters on kilometres: the first nightly run after upgrading processes your whole history at once; on large databases raise `PLACE_VISITS_THROTTLE_SECONDS` beforehand to make it gentler (#2963) - The nightly place-visit job now only processes points that don't yet belong to a visit and pauses briefly between places, so it no longer saturates the database and delays incoming location uploads. The pause is tunable via `PLACE_VISITS_THROTTLE_SECONDS` (default `0.1`) (#2963) - Opening "View on map" for an import on Map v2 now shows only that import's points, instead of every point within the import's date range (#2734) - Place and area visit detection no longer silently finds zero visits for users whose distance unit is kilometers (the search radius was being truncated to 0 by integer division) (#3031). - Points added retroactively through the API or trackers (with timestamps in the past) now get their routes generated, instead of only connecting after a manual data recalculation (#3036). - Photoprism photo imports no longer fail with an HTTP 400: the `after`/`before` filters are now sent as plain `YYYY-MM-DD` dates, as recent Photoprism requires (it rejects the full timestamps shipped in 1.9.2). Results are still bounded in-app by the exact end timestamp, and a blank start date no longer breaks the import (#3034). ## [1.9.2] - 2026-06-25 ### Added - A Flights toggle on the Map v2 trip view shows your AirTrail flights alongside the route and photo overlays, and hides the day-route segments that fall inside a flight so the two don't overlap. The button only appears when an AirTrail URL is configured. ### Fixed - Photoprism photo imports with an end date no longer fail with an HTTP 400: the `before` filter is now sent as a full ISO8601 timestamp instead of a bare date (#1608). - Re-running visit detection no longer raises `ActiveModel::MissingAttributeError` when a cluster contains points already attached to a confirmed visit. ## [1.9.1] - 2026-06-22 ### Added - Trip photos now appear on the Map v2 trip and replay views: thumbnails pop in one at a time as the replay playhead reaches each photo's timestamp, and the same photos are available on public shared-trip links. Photos that fall inside one of your privacy zones are masked from both the map and shared links. ### Fixed - Re-running visit detection no longer creates duplicate suggestions for a visit you already confirmed, even after correcting its address moved the place marker away from the underlying points (#2952) - Adding a per-day trip note no longer fails with "Content missing" on instances upgraded from a pre-release build; a migration backfills the `notes` table columns that an earlier `if_not_exists` table creation could have skipped (#2987) - Reverse geocoding against the hosted `photon.dawarich.app` (and `photon.komoot.io`) now always uses HTTPS, even when `PHOTON_API_USE_HTTPS` is unset or not exactly `true`, fixing the `Geocoder::ResponseParseError` caused by Cloudflare's HTTP→HTTPS redirect (#2982) ## [1.9.0] - 2026-06-21 ### Added - AirTrail integration: Dawarich can pull your flight history from a self-hosted [AirTrail](https://github.com/johanohly/AirTrail) instance and draw the flights as arcs on Map v2. Configure it on the Integrations page (with "Test connection" and "Sync now"); flights also re-sync daily, and the Flights map layer hides overlapping GPS points while enabled. - Run the app and Sidekiq containers under a custom user via `PUID`/`PGID` environment variables: the container starts as root, fixes ownership of the mounted volumes, then drops privileges. Use this instead of Compose `user:`, which cannot write to root-owned volumes (#1159). - Trip detail page redesigned around MapLibre v2: sticky map on the left, scrollable per-day accordion on the right with first/last point time and per-day distance, day-colored routes, photo overlay toggle, and a timeline replay scrubber. - Per-day **trip notes**: add a short plain-text note to any day of a trip directly from the accordion. Notes live in their own `notes` table and are also available via `GET/POST/PATCH/DELETE /api/v1/notes`. - Trip cards on `/trips` and the trip create/edit form now render their map with MapLibre instead of Leaflet, matching Map v2. The form map live-updates the route preview when the trip dates change. - Public sharing of individual **tracks**: a Share button on each track card creates an expiring public link showing that track's route, stats and (optionally) photos. - Public **live-location sharing**: share your current position in real time from the Map v2 Tools tab. Viewers see a single live dot over a public, optionally phrase-protected link; the location updates over a token-gated public channel and respects your privacy zones. - Public shared **trip** pages now mirror the in-app trip layout — sticky day-colored map, a per-day accordion (hover a day to highlight it on the map, click to pin), stats, and a full **replay** scrubber. The trip share form gained per-section toggles to choose exactly what the public page exposes (route, stats, countries, description, day-by-day, per-day notes, photos). - Supporters can now verify by their **GitHub username** as well as email (Settings → General), so GitHub Sponsors whose sponsorship email is private can still get their supporter badge. (#2980) ### Changed - A trip's rich-text **notes** field is renamed to **description**; existing content is migrated automatically. - Per-day trip stats are now computed in a single PostGIS query (`ST_MakeLine`/`ST_Length`) instead of a Ruby Geocoder loop; cache key now also invalidates when individual trip points are updated. - Trip replay now plays back proportional to the real time between points, and the map/trip/public-share pages all share one replay implementation. - Ruby version updated to 3.4.9 ### Fixed - Family Members map layer no longer draws a stray line to the map center when a member location update lacks coordinates (#2863) - Insights and statistics now report the same number of countries visited, excluding fly-over countries without a qualifying city. (#2929) - OIDC login no longer fails with an "Issuer mismatch" error when the provider's issuer ends in a trailing slash (e.g. Authentik); the trailing slash is now preserved instead of being stripped. (#2925) - Trip card preview on `/trips` and the per-day route layer on the trip page now split routes at the International Date Line, so transpacific trips no longer draw an impossible line across the globe. #2731 - Users signed in via Google will now be able to sign in with new password after setting it up, instead of being locked out by the old password being ignored. - Suggested visits now always show a Confirm and Delete control, including visits with no matched place — which previously rendered no action and got stuck with no way to confirm or remove them. #2917 - Searching for a place by name now also matches your areas by name, so an area outside the nearby radius shows up in the results instead of being hidden. #2918 - Dragging the map during replay no longer snaps the view back to the moving marker; auto-follow yields until you reopen the replay panel. - [Cloud] Signing in with Google resolves to a single account across web and mobile, and the account settings page shows which provider an OAuth account is connected with instead of offering a sign-in button. #2969 ## [1.8.1] - 2026-06-11 Upgrade notes: 1. A migration removes duplicate year-end digests that could accumulate before this release. If a yearly recap in Insights showed odd numbers, they may change after the upgrade — that's the duplicates being cleaned up. ### Added - Map v2 settings panel: a **Visit Max Gap** slider to tune the stay-point visit detector's maximum gap (minutes) between points within a single visit. Only shown when the `stay_point_detection` feature flag is enabled (off by default). - Fog of War (Map v2) can now reveal explored areas per hexagon instead of per point, using precalculated monthly statistics. Switch between "Per point" and "Per hexagon" in the map settings panel. (#2899) ### Changed - The suggested-visit card no longer promises alternative suggestions that never arrive; it now points to the visit's search button for picking a different place (#2852) - Loading points on the map is faster on large histories: the points API now uses the spatial index when filtering by the visible map area, instead of scanning every point in the date range - Monthly statistics are lighter to calculate for point-heavy months: hexagon aggregation reads coordinates in a single pass without instantiating database records, and no longer re-queries the whole month when it has to fall back to a lower hexagon resolution - The Timeline day view no longer issues one extra database query per visit, and the initial map view's bounds are computed in a single query instead of two - Bumped the `oauth2` gem to 2.0.22 to close a known credential-leak advisory (GHSA-pp92-crg2-gfv9) on the Google/GitHub sign-in path - CI now runs the full RSpec suite on every pull request; the previous workflow had been disabled - Globe view is enabled by default for Pro and self-hosted users. ### Fixed - Deleting an import no longer gets stuck on an endless spinner: failed deletions revert to a retriable state, and imports stalled in "Deleting" for over an hour show a retry button (#2835) - Insights no longer report a "new country visited" for border-crossing geocoding blips that the statistics pages already filter out; the yearly digest now applies the same rule as the monthly one (#2727) - Deleting points or anomaly points via the map's "Select Area" tool now removes them from the anomalies layer immediately, without requiring a page reload (#2790) - Months with very small distances on the Stats page now render a visible bar and show their tooltip; months without data no longer render a bar at all (#2864) - Weekday labels in the Insights "Activity Overview" heatmap now line up with their grid rows (#2896) - OIDC login no longer fails with "undefined method 'with_indifferent_access'" when OIDC_ISSUER is set to the full discovery URL — the trailing /.well-known/openid-configuration is now stripped automatically (#2056) - Importing files containing invalid UTF-8 bytes (e.g. Windows-encoded degree signs in Google Timeline phone exports) no longer fails with "invalid byte sequence in UTF-8". Applies to the JSON-based importers as well as OwnTracks and TCX (#2772) - Moving a point on Map v2 no longer drags unrelated route lines along with it; routes are rebuilt from the updated points instead of patching nearby line vertices (#2150) - An import that finished successfully could still be marked "Failed" — with a failure notification — when a post-import step (stats scheduling, anomaly filtering) raised after all points were already written; post-import steps no longer affect the import's status - Cloud only: the Lite plan's 12-month data window now applies to the Points page as well, and the "points outside your window" hint no longer caps the visible-points count at the page size - Data recalculation no longer fails with "Year has already been taken" when duplicate year-end digests exist; duplicates are cleaned up automatically and can no longer be created (#2866) - The Anomalies map layer now remembers being enabled across page reloads and day changes, like other layers (#2791) - Map v2 Replay now plays back proportionally to real elapsed time (at 1x, one real minute per second; speed multiplier compresses further) instead of one point per tick, so slow and fast journeys of equal duration take equal playback time; long point-free gaps are skipped quickly instead of stalling (#2845) - The replay marker now renders above track and route lines instead of being hidden beneath them - Deleting a family no longer fails with a 500 error when location-sharing requests exist for it (#2916) - Self-hosted: the /admin/flipper feature-flag UI is no longer rate-limited, which made it unusable after a few clicks (#2897) ## [1.8.0] - 2026-06-08 Upgrade notes: 1. New visit suggestions mode is available, read below on how to enable it. Based on the feedback, it will be enabled for everyone in a future release. 2. If you'd like to delete all suggested visits, run `Visit.suggested.destroy_all` in the Rails console. This will not delete any confirmed visits or places, but it will clear out all suggestions so you can start fresh with the new algorithm. Also, if you'd like to delete all declined visits, run `Visit.declined.destroy_all` to clear those out as well. ### Added - "What's New" changelog notices in the navbar. Self-hosted users are asked once before any external request and the widget loads only after opt-in; Cloud users see it automatically. Toggle anytime in Settings → General, or point it at your own instance with `CHIBICHANGE_WIDGET_HOST` and `CHIBICHANGE_SLUG`. ChibiChange will be open-sourced soon. - Sign in with Apple on the web (Dawarich Cloud only) - Opt-in non-ML "stay-point" visit detection, behind the per-user `stay_point_detection` flag (default off). A single-pass dwell detector that fixes the old clusterer's slow-stay false-rejects and dead-battery gap splits, and stores a 0–100 confidence score per suggested visit (exposed via the API). #2832 Enable (Rails console): `Flipper.enable_actor(:stay_point_detection, user)` for one user, `Flipper.enable(:stay_point_detection)` for everyone, or toggle in `/admin/flipper`. Re-detect past history with `Visits::FullHistoryRedetectJob.perform_later(user.id)`. Tune the longest gap counted as one stay via `stay_max_gap_minutes` (default 60, clamped 5–720). - Map v2 Timeline: every visit now has a search icon to find the real place by name — a type-as-you-go geocoder (Photon) lookup biased to the visit's location, each result showing category, distance, and nearby saved Areas. Pick a result to label the visit or create a new place on the spot; choosing a far-away place asks before relocating it. ### Changed - Declining a visit is now **deleting** a visit. Decline (per-visit, "Delete all" for a day, the bulk bar, and the Map v2 area-selection card) is replaced by **Delete**, which confirms and removes the visit entirely; your location points are always kept. The "Declined" filter and Restore action are removed. ### Fixed - The map's Places layer no longer floods with a marker for every suggested visit — it now shows only places you created manually, attached to a confirmed visit, or tagged. **Heads-up after upgrading:** long-time accounts will see far fewer markers, since every suggested visit used to create its own place (often thousands). Nothing is deleted; suggested-only places are hidden until you confirm the visit or tag the place. `GET /api/v1/places` accepts a `filter` parameter to override: `all`, `manual`, `confirmed`, or `tagged`. - Deleting a single point on the map (via its info card) now redraws the connecting route immediately instead of leaving a stale line until reload. (#2844) - The official Traccar client app is now supported directly. Its payload nests coordinates, battery and activity one level deeper than Dawarich's own client, so its points were silently dropped; both shapes are now accepted. #2741 - Deleting an import now also removes any tracks left with no points, instead of leaving empty "ghost" tracks on the map and timeline. Connected maps drop the removed track right away. #2825 - Mobile menu items at the bottom of the list (e.g. "Family members") are no longer hidden behind the browser's address bar; the map layout now sizes to the dynamic viewport height. (#2249) - Date/time picker icons and other native form controls are now legible on the dark theme, which now declares a dark `color-scheme`. (#2765) - Reverse geocoding no longer stalls behind GPS anomaly detection. The check used to re-scan the whole current month on every incoming location (~30 s late in a busy month) and starve the geocoding queue; it now inspects only the new points plus their immediate neighbours. - Renaming a suggested visit no longer auto-confirms it. Renaming now only changes the name; confirming happens solely through the suggested-place picker. - Map v2 Timeline calendar: the per-day "suggested visits" dot now clears as soon as you confirm or delete the last suggestion for that day, instead of lingering until reload. ## [1.7.11] - 2026-05-31 ### Added - Onboarding "Load demo data" now seeds a fully populated `/map/v2` instantly: 30 days of Berlin + a Prague-weekend trip, ~80 visits with tags and places, and stats anchored to the current calendar month. "Remove demo data" wipes everything in one click while preserving anything you've confirmed, edited, or built on top of (visits, trips, places, tags adopted by user action stay). - Visits can now be manually assigned to one of your saved areas. When you do, the visit takes the area's name automatically — unless you've already given it a custom name, or you've also picked a place (a place name wins over an area name). Available via API now; UI to follow. #2577 ### Changed - Two unused indexes on the `points` table are dropped on upgrade; on large self-hosted instances this frees several GB of disk. - Areas now validate their geometry: radius must be greater than 0, latitude must be within -90…90, and longitude within -180…180. Invalid values are rejected instead of silently saved. - Bumped bundled gems (aws-sdk, devise, jwt, httparty, and others) to close 9 known CVEs. Self-hosters get the security fixes by upgrading. ### Fixed - Cloud only: PostHog exception capture is enabled to help diagnose production errors. - Map v2 Timeline calendar now lights up days that have raw points even before Track or Visit generation has caught up, matching the Insights → Activity Overview calendar. #2579 - Reverse-geocoding flood: duplicate per-point enqueues are now coalesced for 24 h via a Redis dedup key, retries are capped at 3, and the nightly sweep bypasses (and clears) the dedup so points whose retries were exhausted — or whose key still lingers — are picked up on the next run. - Map v2 visits layer now honours the selected date range. Since 1.7.10 the viewport-bounded visits fetch silently dropped the `start_at`/`end_at` filter on the backend, so all visits inside the viewport were rendered regardless of the date filter. #2817 - `POST /api/v1/visits` no longer links a new visit to a place owned by another user. Passing a foreign `place_id` is ignored — the visit gets a place owned by the requester at the requested coordinates, and the response no longer echoes the other user's place id or coordinates. - Map v2 settings panel: "Apply Settings" now actually saves your changes. Points rendering mode, speed-colored routes, live mode, and fog-of-war toggles all persist on click and reload. Apply/Reset buttons moved above the Transportation Mode section so they sit inside the outer form. #2680 - The app no longer trips firewall blocks by repeatedly checking family status when you're not part of a family. ## [1.7.10] - 2026-05-26 ### ⚠️ Upgrade notes - Stops shorter than 5 minutes are no longer suggested as visits by default. Change the threshold under **Map V2 ->Settings -> Visit detection** if you want shorter stops included. - Smart density fill now works correctly (it was broken in 1.7.8–1.7.9). You may see more visit suggestions, especially on days when your tracker recorded points unevenly. ### Added - Map v2 family member markers show name + last-seen datetime on hover. - Map v2 area info card exposes an **Edit** button that opens the area modal pre-filled — rename and resize existing areas without redrawing. Backed by a new `PATCH /areas/:id` route. - Map v2 selection tool: **Delete N Anomaly Points** button appears when the selection contains anomaly points, so you can clean up GPS noise without touching real points. - New **Minimum visit duration** setting under Settings → Visit detection (1–60 minutes, default 5). Raise it to ignore short drive-bys; lower it to catch brief errands. Replaces the hardcoded 3-minute floor that was the same for everyone in 1.7.8–1.7.9. ### Changed - Map v2 side panel only closes via its X button. Create Visit / Create Area / Create Place and clicking a visit marker no longer dismiss the panel — visit/track clicks switch the active tab in place. - Map v2 Visits layer is viewport-bounded: enabling the layer and panning/zooming refetch via `selection=true&sw_lat=…&ne_lng=…` (debounced 400 ms) so a wide date range no longer hauls every visit at once. Timeline day-selection still loads the full day regardless of zoom. - Submitting "Create Visit" auto-enables the Visits layer so the new visit is immediately visible. ### Fixed - Map v2 Place creation modal now closes on successful submit — the success path is no longer gated on a Turbo Stream side-effect, so the modal always dismisses after the place is saved. - Stats page no longer 500s after deleting an import or recalculating a month with no points. #2682 - Timeline no longer fills with `traveled · 0m` rows from stationary keepalive clusters; commutes that absorb adjacent stationary points are correctly labeled by their moving mode (e.g. `drove`) rather than `stationary`. Hit **Settings → Recalculate** to apply to existing data. - New tracks now honor the user's enabled transportation modes during initial detection. Previously only the Recalculate path respected disabled modes, so a user who turned off (e.g.) cycling still saw cycling assigned to freshly built tracks. #2787 - Visit detection no longer suggests stops at places you only drove past. Clusters where the device was moving faster than walking pace between real GPS points are rejected, so road centerlines on busy arterials stop showing up as "visits" to Kent Street / Leach Highway / etc. #2736 #2775 - Visit detection requires real GPS points (not interpolated density-fill ghost points) to meet the minimum-points threshold, so a single drive between two real fixes can't be inflated into a visit. #2736 - Smart density fill now works correctly — it was silently disabled in 1.7.8 and 1.7.9. - Visit detection now respects your **Visit time threshold** setting when deciding where one visit ends and the next begins. The setting was previously ignored and always treated as 30 minutes. ## [1.7.9] - 2026-05-21 ### ⚠️ Upgrade notes - Run **Settings → Recalculate tracks & stats** to merge pre-existing overlapping tracks. #2463 - Visit detection now creates one Place per visit (was up to 25 candidates). Use `GET /api/v1/visits/:id/possible_places` and `POST /api/v1/visits/:id/select_place` for alternatives. The `place_visits` table will be dropped in a follow-up release. - Run after deploy (both safe to re-run): 1. `bin/rails dawarich:backfill_place_names` 2. `bin/rails dawarich:cleanup_suggested_places` ### Added - Public location sharing — share a trip or a timeline date range via a revocable public link, with optional magic-phrase protection and an optional expiry date. Shared routes respect privacy zones; stats are opt-in (off by default) and OG previews are suppressed for phrase-protected links. #2804 - Map v2 **Hexagons** layer (Pro) — H3 cell heatmap, zoom-adaptive resolution. #2568 - Download a trip's points as GPX or GeoJSON from the trip page. #2400 - OIDC PKCE support via `OIDC_PKCE_ENABLED=true` (off by default). #2282 - `POST /api/v1/visits/:id/select_place` — assign a Photon candidate to a visit. - Visits auto-clean their previous Place on reassignment/destroy when it has no notes, tags, or other references. ### Changed - `GET /api/v1/visits/:id/possible_places` returns live Photon suggestions; the assigned place comes first with its `id`, others have `id: null`. - `GET/POST /api/v1/places/nearby` now include `id`, `source`, and `geodata` per item (additive). - `Place#has_many :visits` is now `dependent: :nullify` — deleting a Place no longer deletes its visits. ### Fixed - `select_place` validates lat/lon bounds (422 on out-of-range) and serializes concurrent calls via PG advisory lock to prevent duplicate Places. - `select_place` dedups by name + 50 m proximity instead of `geodata` JSONB, working regardless of `STORE_GEODATA`. - Self-hosted instances no longer 500 on Stats/Insights when `JWT_SECRET_KEY` is unset; `/trial/upgrade` now redirects home. #2682 - Imports table shows duplicate-skip counts and notifies when an import is all duplicates. #2721 - Family members' positions update in real time instead of every 60 s. #2733 - Immich/Photoprism photos reappear after a transient empty response (no more 30-minute hidden window). #1071, #784 - Map v2 **Select Area** includes anomaly points so bulk-delete works on them. #2476 - Map v2 area-selection: restored the "Delete N Points" action that disappeared in 1.7.8. Pro / self-hosted, confirmation prompt, capped at 5,000 per request; recalculates affected tracks and monthly stats. #2754 - Timeline day click no longer corrupts the Search end-time; fields match date-picker minute precision. #2624 - Map v2 speed-color gradient editor saves and applies correctly. #2120 - Trips respect the GPS anomaly filter for route, distance, and countries. Run **Recalculate trip** to refresh existing trips. #2474 - Bulk and single point deletion recalculate affected tracks. #2496 - "Recalculate tracks & stats" and "Re-evaluate past data" skip anomaly points, matching real-time generation. #2630 - Trip photos appear on sub-day trips (timestamps no longer truncated to dates). #2708 - Tracks no longer split into overlapping segments when points arrive late/out of order; same-device overlaps auto-merge on the next run. #2463 - Same-tracker boundary merging skips tracks more than 5 km apart (no more GPS-jump fusion). - Visit place cleanup runs in `Places::DeleteIfOrphanJob` instead of inline `after_commit`. - `DataMigrations::BackfillPlacesUserIdJob` correctly excludes just-assigned places from the orphan-delete pass. - Real-time track boundary detector skips the per-track scan when no untracked points exist. - Bulk visit suggestion accepts both `user_id:` and `user_ids:` to survive stale Sidekiq jobs. #2740 - `RemoveUnusedIndexes` migration drops invalid `points` indexes left by failed `REINDEX CONCURRENTLY` before removing unused ones. #2124 - Vendored `h3-js` retains its upstream Apache-2.0 license header. - Insights "Top Visited Locations" no longer underreports days for multi-month totals (e.g. 133 days rendered as "4 days"). #2743 ## [1.7.8] - 2026-05-16 ### ⚠️ Upgrade notes - **Self-hosters running OIDC-only sign-in:** the `ALLOW_EMAIL_PASSWORD_REGISTRATION` env var no longer doubles as a login gate. Email/password sign-in is now controlled by the new `ALLOW_EMAIL_PASSWORD_LOGIN` env var (defaults to `true`). To preserve OIDC-only sign-in after upgrade, set `ALLOW_EMAIL_PASSWORD_LOGIN=false`. - **Visit detection rewrite:** the next nightly run after upgrade will produce different suggested visits. Confirmed visits and named places are preserved; only suggestions change. - **Places backfill (irreversible):** the place-ownership migration backfills `places.user_id` from owning visits and **permanently deletes any place that has no linked visits**. Multi-user instances and instances with orphan rows from prior bugs should run `rake places:backfill_user_id_dry_run` first to see assigned/deleted counts. Single-user self-hosted instances are unaffected. The follow-up release will add a `NOT NULL` constraint, so any new places created between this release and the next must carry a `user_id`. - **Historical tracks auto-recalculate on upgrade.** A background job backfills `points.tracker_id` from each point's `raw_data` (Google `deviceTag`, OwnTracks `tid` — both stored as-is) or its `import_id` (`legacy-import-`, visible in points and tracks API responses for backfilled rows), then recalculates stats, tracks, and digests for every user with tracks predating the fix. The enqueue job is Sidekiq-retry-safe and re-checks its predicate on each retry, so a crashed/restarted Sidekiq resumes cleanly without re-processing finished users. New installs are unaffected. - **Expect a temporary spike during the recalc window.** Per-user jobs are staggered over the first hour; expect elevated Sidekiq queue depth, CPU, and database IO until they finish, with duration scaling by user count and history length. Tracks may appear merged on the map for individual accounts until their recalc completes. - **2FA lockout recovery on instances without SMTP:** the new 10-attempt 2FA lockout sends an unlock email; self-hosters without SMTP configured will not receive it. Locked users can be unlocked from the Rails console with `User.find().reset_failed_otp_attempts!`, or by completing the password-reset flow (which also clears the lockout). ### Changed - Visit detection now uses PostGIS spatial clustering for faster, more accurate stops; the iteration-based detector is removed. - Places are now strictly per-user. Suggestion, photo-geotagging, and reverse-geocoding all use your own place catalogue exclusively; no places are shared across users. Existing shared places have been backfilled to their most-active owner. Self-hosted single-user instances see no behaviour change. ### Added - "Re-run detection on full history" button under Settings → Visits. Confirmed visits and named places are preserved. - Account lockout after 10 failed 2FA attempts (30-minute auto-unlock or password reset). Applies to both the mobile API (`POST /api/v1/auth/otp_challenge`) and the web sign-in flow. Backup codes still work during a lockout so users with one stored can recover immediately. A notification email is sent to the account owner when a lockout is triggered. #2575 ### Fixed - Fix support of FIT files from Garmin Connect. #2686 - The Anomalies map layer no longer requires manually toggling off and on after a page reload or timeframe change. The toggle state is restored on reload, and the layer refetches anomalies for the active date range. #2568 - Email/password login is now shown alongside the OIDC button on self-hosted instances by default, instead of being hidden whenever OIDC is configured. Operators who want to enforce OIDC-only sign-in can set `ALLOW_EMAIL_PASSWORD_LOGIN=false`. See the upgrade note above. #2495 - Suggested visits at residential addresses are no longer stuck on the placeholder name "Suggested place" indefinitely. The nightly place-naming job now assembles a name from street, house number, city, and state when the geocoder response has no top-level place name — matching how new visits are named at creation time. #1711 - Photos imported from Immich now display at the correct time on Map v2 and import with the correct UTC timestamp, regardless of the host server's timezone or the photo's capture timezone. Previously, photos taken outside the server's timezone could appear up to 24 hours off. Existing imports keep their old timestamps; to fix already-imported photos, re-run the Immich import from **Settings → Integrations → Immich**. The photos API now exposes a `capturedAt` field with the canonical UTC instant (from Immich's `fileCreatedAt` / PhotoPrism's `TakenAt`) alongside the existing `localDateTime` key, which continues to return the source's wall-clock value. Map v2 uses `capturedAt` for time display. #2253 - Confirmed and declined visits inside an area or assigned to a place are no longer reverted to "suggested" — and any name you gave them is no longer overwritten — by the nightly visit-recompute job. #2048, #2484 - GPX import now streams the file rather than loading the entire XML into memory, so multi-hundred-MB GPX files (e.g. long-running activity exports) no longer OOM the Sidekiq worker. #2296 - Viewing an import on Map v2 or the Points page now selects the import's full date range, instead of defaulting to today or the last month. #1857 - Imports (GPX, KML, GeoJSON, FIT, TCX, Google Timeline, OwnTracks .rec, CSV, Polarsteps) now generate tracks for the imported point range. To rebuild every track in a range — including manually-corrected ones — use Map v2 → Settings → **Recalculate tracks & stats**. #2224 - Tracks recorded by multiple devices on the same account (phone + watch + GPS unit) no longer get merged into one zigzagging track on the map. Each device's points are kept on their own track, and Map v2 draws routes per-device. #337, #1726 - Importing a GPX file with multiple `` or `` elements no longer merges them into a single track when timestamps overlap or arrive out of order (e.g. Garmin daily-file exports); each track and segment becomes its own track. When a `` declares ``, that value is SHA1-hashed and used as a stable device identity so consecutive imports of the same device stay on the same track stream; with only ``, identity is scoped to the import filename to prevent unrelated devices from colliding. #1726 - Importing a Google Records.json export with positions from more than one device no longer "teleports" between devices and inflates distance travelled; points are scoped per-device using Google's `deviceTag`. #337 - The `tracks` unique index now scopes by `tracker_id` (via a `COALESCE(tracker_id, '')` expression so legacy NULL-tracker rows still can't duplicate), letting two devices produce a journey with the same start/end timestamps on one account without colliding on insert. ## [1.7.7] - 2026-05-09 ### ⚠️ Breaking changes **Prometheus metrics backend migrated to Yabeda.** Dawarich now uses the Yabeda monitoring framework instead of `discourse/prometheus_exporter`. Self-hosters who scrape Prometheus metrics from Dawarich should update their configuration. If Sidekiq is unreachable during a scrape, web returns its own metrics only and logs a warning. Prometheus sees a momentary gap in `sidekiq_*` rather than a failed scrape. **Scrape target** (requires HTTP basic auth with `METRICS_USERNAME` / `METRICS_PASSWORD`): - Web: `http://dawarich_app:3000/metrics` **Custom `dawarich_archive_*` metric names are unchanged.** Dashboards and alerts built on these metrics continue to work. **Infrastructure metric names have changed.** If you have dashboards built on `ruby_*`, `active_record_*`, or similar metrics emitted by `prometheus_exporter`, you must update them: | Category | Before | After | |---|---|---| | HTTP requests (total) | `ruby_http_requests_total` | `rails_requests_total` | | HTTP request duration | `ruby_http_request_duration_seconds` | `rails_request_duration` | | Sidekiq job count | `ruby_sidekiq_jobs_total` | `sidekiq_jobs_executed_total` | | Sidekiq failed jobs | `ruby_sidekiq_failed_jobs_total` | `sidekiq_jobs_failed_total` | | Sidekiq job duration | `ruby_sidekiq_job_duration_seconds` | `sidekiq_job_runtime_seconds` | | Sidekiq queue latency | `ruby_sidekiq_queue_latency_seconds` | `sidekiq_queue_latency` | | Sidekiq queue backlog | `ruby_sidekiq_queue_backlog_total` | `sidekiq_jobs_waiting_count` | | Sidekiq process count | `ruby_sidekiq_process_count` | `sidekiq_active_processes` | | Puma workers | `ruby_puma_workers` | `puma_workers` | | Puma backlog | `ruby_puma_request_backlog` | `puma_backlog` | | Puma thread pool capacity | `ruby_puma_thread_pool_capacity` | `puma_pool_capacity` | | ActiveRecord pool | `active_record_connection_pool_connections` | `activerecord_connection_pool_size` | | Process/GC (e.g. `ruby_rss`, `ruby_heap_live_slots`) | emitted | not emitted by default; add a custom Yabeda group if needed | **Removed environment variables:** - `PROMETHEUS_EXPORTER_HOST`, `PROMETHEUS_EXPORTER_HOST_SIDEKIQ` — no longer needed. Metrics are served in-process by each application. **Retained environment variables:** - `PROMETHEUS_EXPORTER_ENABLED` — still the single on/off switch. - `METRICS_USERNAME`, `METRICS_PASSWORD` — unchanged. - `PROMETHEUS_EXPORTER_PORT` — port the in-process Sidekiq metrics exporter binds to (default 9394). **New optional environment variable:** - `SIDEKIQ_METRICS_URL` — internal URL the web container uses to fetch Sidekiq metrics (default `http://dawarich_sidekiq:9394/metrics`). Override on Dokku, Kubernetes, or any deployment where the worker container's hostname differs from the docker-compose default. **Prometheus scrape config example:** ```yaml scrape_configs: - job_name: dawarich metrics_path: /metrics basic_auth: username: prometheus # set via METRICS_USERNAME password: prometheus # set via METRICS_PASSWORD static_configs: - targets: ['dawarich_app:3000'] ``` ### Fixed - Fixed monthly stats failing with a "Stats update failed" notification when the month's distance exceeded the int4 limit (2,147,483,647 m ≈ 2.15M km). Affected months stayed stuck on the prior value until recalculated. #1996 - 500 error on the imports page. #2683 - Insights weekly pattern now refreshes after monthly stats change, instead of showing a stale snapshot until the next monthly digest job runs. #2478 - Points with no reverse-geocoding result (ocean, wilderness) are now marked as attempted instead of being re-queued every nightly run; use "Start Reverse Geocoding" to retry after switching providers. #2271 - Activity detection now falls back to displacement when the tracker reports 0 m/s, so OwnTracks Significant Change mode and similar low-power setups stop misclassifying real movement as stationary. Run **Map v2 → Settings → Recalculate tracks & stats** to apply to existing tracks. #2390 - Redis no longer balloons (multi-GB) when browsing photos with Immich or Photoprism connected. Photo thumbnails are no longer copied into the server-side Redis cache; the browser caches them directly via `Cache-Control` instead. #1609 - Drag-selecting a region on the map now includes visits attached to your saved Areas (Home, Work, etc.), instead of silently dropping area-only visits from the visit tray. #2420 ## [1.7.6] - 2026-05-09 ### Added - Map v2 timeline: bulk Confirm and Decline in selection mode, capped at 500 visits per request. - Trip **Recalculate** button: refresh path, distance, and visited countries on demand. The page updates automatically when it finishes; repeat clicks within 60 seconds are ignored. #2478 - Google's "Timeline Edits.json" type of Takeout export is now recognized and imported directly. ### Fixed - Monthly stats now bucket points by your local timezone instead of UTC — fixes phantom day-1 spikes from overnight imports and undercounts near month boundaries. #2546 - Slider knobs in settings and map-layer toggles now move on click instead of staying left while only the track color changes. #2566 - Stats and tracks recalculation no longer crashes in midnight-DST timezones (e.g. `America/Santiago`). #2638 - Mobile map fills the dynamic viewport and respects iPhone safe-area insets — navbar below the notch, date selector / demo banner above the home indicator and Safari URL bar. #1873 - Transactional emails now build links with HTTPS, fixing reset links that arrived as `http://` even when the site was served over HTTPS via reverse proxy. #1469 - SMTP authentication and timeouts (`SMTP_AUTHENTICATION`, `SMTP_OPEN_TIMEOUT`, `SMTP_READ_TIMEOUT`) are now env-configurable — Office 365 and similar no longer need a custom initializer. #1469 - Export zip entry timestamps no longer drift across timezones (was 7h ahead on US Pacific). Applies to per-export and full-archive downloads. #2639 - Map v2 heatmap stays visible at city and street zoom instead of fading out past city level. #2087 - Map v2 search panel: visits list no longer flashes and disappears after picking a location — a stale debounced fetch was overwriting it. #2394 - Transportation-mode sliders (Walking/Cycling/Driving max speed, Min flight distance) in Map v2 settings now respect your unit of measurement (mph/mi when miles are selected). #2634 - Self-hosting docs (Docker, Synology, intro) now show the correct default password `safepassword` instead of `password`. #2636 - Map v2 light/white/grayscale basemaps: dense point sequences no longer camouflage as thin white lines — strokes are now dark on light basemaps, white on dark. #2387 - Activity Overview heatmap opens centered on your most recent active day instead of January 1 — no blank future months on mobile early in the year. #2228 - Map v2 timeline calendar: a selected day shows visits in your profile timezone — late-evening visits no longer leak across day tabs. #2619 - Renaming a suggested visit in the timeline now confirms it and saves the typed name as a place under your account. #2621 - User-data archive import no longer lets the payload overwrite a track's `user_id`, `id`, or timestamps. - Track generation no longer creates duplicate tracks — multiple background jobs (daily, realtime, recalc, import) could previously produce the same track per time window, leaving 2–3 copies on your map. Run **Map v2 → Settings → Recalculate tracks & stats** once after upgrading to recompute from the merged points. #2677 - Heatmap on Map V2 looks a lot better than before - In notifications section of navbar only "99+" is shown when there are more than 99 notifications, instead of the actual number. ## [1.7.5] - 2026-05-04 ### Added - Manual transportation-mode correction per segment in the map view, with a one-click reset to auto-detection. Manually-corrected segments are preserved across re-classification. #2405 - Per-user transportation-mode allowlist in the map settings panel. Disabled modes are excluded from auto-detection going forward; existing tracks stay as they are until you press "Re-classify my history". #2405 ### Fixed - Track duration and average speed are now refreshed whenever a track's path is rebuilt (e.g. after a merge), instead of keeping their pre-merge values. To heal tracks already affected, click Map v2 → Settings → **Recalculate tracks & stats** once after upgrading. - Visited-country statistics no longer count countries that were merely flown over. Points moving faster than 500 km/h are now excluded from the country and city aggregation. Trains and high-altitude cities (Denver, Mexico City, La Paz, Lhasa, …) continue to count as visited. Previously-saved monthly stats are not recomputed automatically — re-run stats calculation to refresh historic months. #1917 - Server-rendered timestamps (Points, Places, Imports, Exports, account settings, trial banner) now display in the user's profile timezone, matching the Maps tab. Previously, the time and tooltip could fall back to the server's default zone, drifting by hours. Invalid stored timezones no longer raise. #1824 - "Start Reverse Geocoding" now actually re-runs for every point in your database — previously it silently skipped any point that had already been geocoded, even though the button promised a full re-run. #2141 - Map v2 date-navigation arrows (`<` / `>`) now shift the time window by exactly one day, matching Map v1. Previously they shifted by the current window width, so a 00:00–23:59 selection paged back by 23h59m instead of 24h. #2548 - Daily track generation now merges a newly-created track with the immediately-preceding existing track when they are seconds apart, instead of leaving a permanent split each time live tracking briefly pauses. To heal splits that have already accumulated in your database, open Map v2 → Settings → **Recalculate tracks & stats** once after upgrading; from then on the daily job will keep adjacent tracks merged on its own. #2265 - The Maps v1 area-drawing toolbar no longer disappears after toggling the Areas layer or refreshing the page. #1938 - Trip page no longer shows an indefinite "loading" spinner in the Countries card when no country data is available; an em-dash placeholder is shown instead, matching the modal's "No countries data available yet." message. #1831 - Trips that cross midnight in the user's timezone now contribute distance and time to both calendar days, instead of being attributed entirely to the day they started. The timeline day summary, the calendar heat grid, and adjacent-day km totals all reflect the trip on each day it actually spans. #2544, #2546 ### Changed - "Start Reverse Geocoding" and "Continue Reverse Geocoding" now enqueue Sidekiq jobs in bulk batches of 1,000 instead of one round-trip per point. For large databases (millions of points) this drops the enqueue phase from minutes to seconds. Per-point geocoder rate-limit behavior is unchanged. #2141 - Map (Leaflet) on mobile browsers no longer clips the bottom of the map and routes after the address bar collapses or the date is changed. #2000 - Visit suggestions are now generated from live tracking (Dawarich iOS app, OwnTracks, Overland, Traccar), not just from imports. Previously, only imported data triggered visit detection. Visit suggestion still requires a configured reverse geocoder (Photon, Geoapify, Nominatim, or LocationIQ). #1749, #1966 ## [1.7.4] - 2026-05-03 ### Fixed - Cloud Trial users are no longer limited to 10 MB import files. - Self-hosted instances no longer need to set `JWT_SECRET_KEY`. #2570 - QR sizes are fixed. #2479 - Family owners can now remove other members directly from the family page. #2555 - Insights and statistics now agree on the number of countries visited per month. #2581 - The default password for the demo account has been changed to `safepassword`. The old default `password` prevented seeds from running due to the new 12-character minimum password length validation. Existing users were not affected. #2593 ## [1.7.3] - 2026-05-02 ### Security Fixes for several issues found in a static-analysis security audit. None of these have a known in-the-wild exploit, but operators should still upgrade. - Path traversal in user-data archive import (`POST /settings/users/import`) — a malicious archive whose JSON manifest referenced files via `..` could attach arbitrary host files (e.g. `config/master.key`, `/proc/self/environ`) to the user's import record and download them. - OAuth web callback (Google / GitHub / OIDC) used to silently link an existing local-password account to an incoming OAuth identity on email match, with no `email_verified` check or consent. The web flow now mirrors the mobile-API flow: the user must confirm the link. - SSRF blocklist for the `immich_url` / `photoprism_url` settings missed RFC1918, CGNAT, IPv6 ULA, multicast and reserved ranges. Cloud installs now reject those; self-hosted gets a smaller blocklist that still catches non-http schemes, cloud-metadata IPs and multicast while permitting LAN / loopback / Docker DNS. - Web OTP challenge (`POST /users/otp_challenge`) had no rate limit, leaving 2FA brute-forceable given a leaked password. Added rack-attack throttles (5/15min per session, 20/15min per IP) plus an in-controller cap of 5 invalid attempts. - Stored XSS via `family.name` rendered through `notification.content.html_safe` is now passed through `sanitize`. - Disabling 2FA now requires both the password AND a current authenticator code (or backup code), on web and API. - Default `prometheus` / `prometheus` credentials for `/metrics` are gone — the endpoint refuses until both `METRICS_USERNAME` and `METRICS_PASSWORD` are set. - Devise minimum password length raised from 6 to 12. - API keys generated by new accounts are 256-bit (was 128-bit). Existing keys keep working. - OwnTracks point ingest replaces a blanket `params.permit!` with the documented field whitelist. ### Added - Polarsteps support — `locations.json` and segment-array exports now import directly. - Files with unsupported extensions are rejected in the browser before upload starts. - Clear, actionable error messages when an unsupported file is uploaded — points to the right file in your Takeout instead of a generic "Unable to detect file format". ### Changed - Monthly and yearly email digests now hide countries and cities with 1 hour or less of time spent, so the Top Countries / Top Cities lists no longer get padded with `0h` and `1h` entries. - Disabling 2FA via `/settings/two_factor` now asks for both your password and a current authenticator code (or one of your backup codes). The web form has been updated; API clients must send `password` AND `otp_code` to `DELETE /api/v1/users/me/two_factor`. - Setting a new password (signup, password change, password reset) now requires at least 12 characters. Existing shorter passwords still work for sign-in. - **`/metrics` endpoint**: if you scrape Prometheus metrics, set `METRICS_USERNAME` and `METRICS_PASSWORD` in your environment. With them unset, `/metrics` now returns 503. - **OAuth (web) without SMTP**: a user signing in via OIDC/GitHub/Google for the first time when an email-matching local account already exists is no longer auto-linked. They are sent to a password-challenge page where entering their existing Dawarich password completes the linking. **No SMTP setup is required for this path.** A "send me a confirmation email instead" button on the same page is the SMTP-based fallback for users who have forgotten their password. - **Self-hosted Immich/PhotoPrism URLs**: the next save of these settings re-validates the URL. Configurations using non-http schemes, `0.0.0.0`, multicast IPs, or the cloud-metadata `169.254.169.254` will be rejected. Standard LAN / Docker / loopback URLs continue to work. ### Fixed - Google Phone Takeout `location-history.json` now imports reliably. (#2437, #2587) - KMZ files from a wider range of exporters now import. - Imports no longer fail intermittently with `No such file or directory @ rb_sysopen - /tmp/...`. #2446 - FIT files from non-Garmin devices and phone apps now import. - CSV files with quoted headers (e.g. `"Latitude","Longitude"`) are now recognized. - Empty (0-byte) uploads now produce a clear error instead of crashing. - Upgrades from older versions (≤ 1.3.1) no longer crash during `db:migrate`. #2576 ## [1.7.2] - 2026-04-29 ### Removed - `rails_pulse` performance monitoring has been removed entirely. The gem, its initializer (`config/initializers/rails_pulse.rb`), the `/rails_pulse` route mount, the scheduled `RailsPulse::SummaryJob` and `RailsPulse::CleanupJob` cron entries, and all `rails_pulse_*` tables are gone. A new migration `DropRailsPulseTables` cleans up existing installations on upgrade. This resolves a class of upgrade failures where the `rails_pulse_*` tables ended up missing/half-applied on production. #2549 ### Added - Swagger docs for all the recent API additions and changes, improving API discoverability and client generation. The full OpenAPI spec is available at `/api-docs`. - Map v2: Delete button on the point info card. Selecting a point now offers an immediate Delete action (with confirm dialog), matching the long-standing Map v1 behavior. The deleted point is removed from the points layer in place without a full reload. ### Fixed - Monthly and yearly digest emails now convert distance from stored meters to the user's preferred unit (km/mi). Previously the raw meter value was shown next to the unit label (e.g. `500000 km` instead of `500 km`). - Map (Leaflet): route lines no longer revert to their pre-move shape when an unrelated point is deleted after dragging another point. The dragend handler was failing to update the marker array because it looked for the controller in the wrong place. #1797 - Track creation now caps a single track's distance at 100,000 km (with a logged warning) instead of silently truncating at the legacy 999,999 m limit. Long-haul journeys are no longer collapsed to ~1000 km. #1693 - Dev container: bind-mount the project root into the container so `bundle install` can locate the `Gemfile`. Previously only sub-paths were mounted, leaving `/var/app/Gemfile` missing. #1804 - Map v2: photos without GPS metadata (`latitude`/`longitude` null) no longer render as markers at Null Island (0°, 0°) — they are now correctly excluded from the photos layer. (#2464, #2465) ## [1.7.1] - 2026-04-28 ### Added - API endpoints for mobile authentication. - New ingest endpoint `POST /api/v1/traccar/points` for the Dawarich mobile client and any compatible Traccar-style tracker. Accepts a single nested-JSON location payload, upserts the point, refreshes the points counter, and triggers anomaly filtering, realtime track regeneration, and the live broadcaster — exactly like the OwnTracks and Overland endpoints. **Configuration** | Setting | Value | | --- | --- | | URL | `https:///api/v1/traccar/points?api_key=` | | Method | `POST` | | Content-Type | `application/json` | Find your API key under **Settings → Account**. **Payload** ```json { "device_id": "iphone-jane", "location": { "timestamp": "2026-04-23T12:34:56Z", "latitude": 52.52, "longitude": 13.405, "accuracy": 5, "speed": 1.4, "heading": 90, "altitude": 42, "is_moving": true, "odometer": 1200, "event": "motionchange" }, "battery": { "level": 0.85, "is_charging": true }, "activity": { "type": "walking" } } ``` Required fields: `location.latitude`, `location.longitude`, `location.timestamp` (ISO 8601). Everything else is optional. Speed is expected in m/s. Battery level is expected as a 0-1 fraction (Dawarich stores it as 0-100). **Response**: `200 OK` with empty array on success. Malformed payloads (missing required fields, unparseable timestamp) return `200` and are silently dropped — same behavior as the OwnTracks and Overland endpoints. Authentication failures return `401`. Unexpected server errors return `500`. Full schema available at `/api-docs`. ## [1.7.0] - 2026-04-26 The Timeline Release The Timeline Feature in Map V2 is now a feature capable to fully replace Google Timeline's user experience and overshine it. Please enjoy responsibly. ### Added - Monthly digest emails. On the 2nd of each month users receive an email summarizing the previous month with an ASCII-rendered overview (distance, active days, countries, cities), a weekly pattern bar chart, a daily distance sparkline, top countries and cities by time spent, first-time visits, and a month-over-month trend comparison. Enabled by default; opt out at Settings → Email Preferences. - Visible, selectable family invitation URL under each pending invite on the family page, so self-hosted instances without SMTP can still share the link #2438. - User-configurable GPS noise filtering in Map v2 → Settings. The accuracy threshold (previously a hardcoded 100 m) is now adjustable from 50–1000 m, and the filter can be disabled entirely, so trips on trains or other weak-signal data sources no longer get their legitimate points stripped out. A "Re-evaluate past data" button clears existing anomaly flags, re-runs the filter with the new settings, and rebuilds tracks/stats/digests; a separate "Recalculate tracks & stats" button rebuilds derived data without touching anomalies. Fixes #2480. ### Changed - S3 storage can now be used in self-hosted mode. It's compatible with S3-like backends, such as MinIO, Ceph, or Cloudflare R2. To enable S3 storage, set `STORAGE_BACKEND=s3` and provide `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, and `AWS_BUCKET`. For S3-compatible backends, additionally set `AWS_ENDPOINT_URL` (or `AWS_ENDPOINT`). - The Timeline tab in Map v2 Tools panel is now a first-class feature. - The single digest email toggle in Settings has been split into independent **Monthly Digest** and **Year-End Digest** controls. A data migration preserves explicit opt-outs: users who had previously disabled digest emails stay opted out of both; users with no preference default to both on. - The Year-End Digest email has been rewritten with ASCII-rendered charts (activity heatmap, monthly distance bars, top countries, year-over-year trend). Content renders identically in HTML and plain-text email clients without JavaScript or external images, fixing rendering issues in Gmail and Outlook. - Points exports (GeoJSON and GPX) are now stored on S3 as single-entry zip archives. Downloads are delivered as `.zip`. - Import uploads are compressed client-side before upload. Users who previously uploaded uncompressed files see no behavior change; S3 storage for new uploads drops substantially for text formats. - Trial users' 10 MB import-file size limit applies to the uploaded file before any client-side compression, so the user-facing limit is unchanged. ### Fixed - Fix yearly digest emails not being sent automatically. The scheduling job existed in the codebase but was never wired into `config/schedule.yml`, so no year-end emails went out. Yearly digests now fire on January 2nd at 06:00 UTC. - Fix a latent race in the yearly digest pipeline where the email job was scheduled with a 30-minute delay after the calculation job; if the calculation took longer than 30 minutes (e.g., Sidekiq backpressure, transient retries), the email was silently dropped. Emails are now chained from the calculation job's success path. - Fix visit name being overwritten by the location name when updating a visit via the map popup. The custom name typed into the "Visit Name" field is now preserved; the place name is only used as a default when the user leaves the name blank #1915. - Fix stray "Map layer preferences saved" flash (and spurious settings requests) when deleting a point on Map v1. Layer-preference saves are now suppressed while the delete flow internally rebuilds the routes layer and layer control #1902. - Fix the Map v2 replay slider showing times in the browser's local timezone instead of the timezone configured in Settings. Day buckets and the minute-of-day index are now computed in the user's timezone so the replay scrubber matches the rest of the app #2457. - Fix "View on map" to use the preferred map. #2475 - Fix a bug allowing inactive users to create points via the API. - Fix country name canonicalization on the Stats page producing wrong results (e.g., France showing as "Scarborough Reef") when the `countries` table has multiple rows sharing the same ISO code #2434. - Fix Stats dashboard charts stuck on "Loading..." for some years due to duplicate Chartkick element IDs when rendered inside cached year partials #2453. - Fix map date-navigation prev/next buttons always shifting by one day; they now shift by the currently selected interval #1736. - Fix individual points occasionally rendering on top of dense point lines on Map v2 by adding a deterministic timestamp-based sort key #2388. ## [1.6.1] - 2026-04-02 ### Added - Info badge on import form suggesting users zip large files (200MB+) before uploading. - Missing SVG icons for activity breakdown (ship, circle). ### Fixed - Fix compressed zip files failing to import with "No such file or directory" error. Rubyzip needs to re-open the source zip for compressed entries, but the temp file could be garbage collected before extraction completes #2446. - Fix anomaly filter crashing on large imports (millions of points) due to loading all points into memory at once. Speed-based filtering now processes data in monthly chunks. ## [1.6.0] - 2026-03-29 ### Added - Immich users can now enrich their photos with geodata. - Users can now optionally enable two-factor authentication (2FA) for their accounts in Settings > Two-Factor Authentication. Supported methods: TOTP apps (Google Authenticator, Authy, etc.) and backup codes. Once enabled, users will be prompted for a 2FA code on login. This adds an extra layer of security to protect your location data. ### Fixed - Fix OIDC account linking failing when the email from the identity provider has different casing than the existing Dawarich account #1983. - Fix confirmation dialogs being ignored when clicking "Cancel" — destructive actions (account deletion, import/export deletion, place deletion) fired regardless of user choice due to Rails UJS and Turbo both handling the same click #1978. - Fix Year in Review share link being empty when toggling public access #2418. - Fix address field on Points page being empty when geodata properties are unavailable #2419. - Fix Stats API returning the same country/city count for every year instead of per-year counts #2280. - Fix flyover countries (with no visited cities) still showing in monthly stats views #2423. - Fix importing Google Timeline files. #2427 ## [1.5.1] - 2026-03-28 ### Fixed - Fix points and tracks interactions on Map v2 being unresponsive after the latest update. - Fix creating demo data from the onboarding modal. - Fix navbar for cloud trial users. - Reset months stats instead of deleting when there is no data. ## [1.5.0] - 2026-03-28 ### Added - GPS noise filtering. An automatic system to detect ahd filter out points with unrealistic speeds, altitudes, or sudden jumps. - Support for signing in via web view using our Android app. - On the map settings page user now can enable and disable map layers. - Onboarding modal now offers a third option to load demo data (3 days in Berlin, ~1000 points) so new users can instantly see what the map looks like. Demo imports bypass trial limits, are clearly labeled with a "Demo" badge, and can be deleted from a banner on the map page or from the imports list. - New tool to the Map V2 tools: The "Day per Country" button will open a modal showing a breakdown of how many days the user has spent in each country, based on their points data. This is calculated by grouping points by country and counting unique days with at least one point in that country. ### Changed - [Cloud] The point creation API endpoints are being excluded from the default Lite/Pro rate limits (200/1,000 requests/hour). They now have general rate limits of 10,000 requests/hour. - Buildings numbers on map V2 are now shown on closer zoom. ### Fixed - Users who registered via Google (or other OAuth providers) can now change their password and email without needing to enter their current password. - Fix deadlocks in reverse geocoding job when multiple Sidekiq workers update points concurrently. - Fix `counter_cache_column` error in points counter reset job by using direct SQL count instead of `reset_counters`. - Fix duplicate place records causing `ON CONFLICT` cardinality violations during reverse geocoding. - Fix `TypeError` crash in transportation mode backfill when Google export files have unexpected JSON structure. - Fix inability to disable visit suggestions background job due to conflicting Rails UJS and Turbo handlers causing request cancellation #2118. - Fix visit confirm/decline buttons firing twice #2379. - Fix clicking on a point in Map v2 silently moving it to the cursor position. Points now only update when intentionally dragged #2149, #2150. - Fix visit name suggester not recognizing Photon reverse geocoding data format, causing all suggested places to show as "Suggested place" #2151, #2377. - Fix visit edit form displaying UTC times instead of the user's configured timezone #2168. - Fix export deletion failing when the export file was manually removed from disk #915. - Fix PhotoPrism `before` date filter being off by one day, excluding photos taken on the end date #747. - Fix datetime inputs allowing 5-digit years on Chrome by adding `max` attribute to all datetime-local fields #578. - Fix Points page datetime fields requiring seconds input, preventing search on mobile browsers and some desktop browsers #1040, #1478. - Fix altitude values being truncated to integers instead of preserving decimal precision #1573. - Fix suggested visits keeping "Suggested Visit" name when confirmed directly without selecting a place #1725. - Fix visit name becoming empty and uneditable when clicking the name field and then clicking away #1776. - Fix trips page crashing with `undefined method 'coordinates' for nil` when trip path calculation hasn't completed yet #1356, #1765. - Fix Immich/PhotoPrism photos on map not being filtered by the selected date range #1755. - Fix short trips (less than one full day) not showing photos due to PhotoPrism `before` date filter being exclusive #1688. - Fix health check endpoint (`/api/v1/health`) triggering unnecessary `User Load` database queries on every request #1770. - Fix points created via Overland API (Home Assistant, GPSLogger) not being automatically reverse geocoded after creation #1242. - Fix monthly stats map crashing with `Invalid LatLng object: (NaN, NaN)` when points have missing coordinates #1762. - Fix trips failing with self-signed certificates by leveraging per-integration SSL skip settings #455. - Fix non-admin users unable to access Background Jobs settings to trigger reverse geocoding or manage visit suggestions #1714. - Fix family page map not loading due to `escape_javascript` producing invalid JSON in the Stimulus data attribute. - Fix countries appearing in visited statistics despite only being driven through without spending meaningful time in any city #1595, #1779. - Fix `migrate_to_new_storage` rake task crashing when export URL is blank, already migrated, or points to a directory instead of a file #1018, #1037. - Fix selecting the only suggested place for a visit having no effect because the dropdown `change` event never fires with a single option #471. - Fix city duration calculation undercounting time spent due to integer division truncating sub-minute GPS intervals to zero #2408. - Fix tooltips in data tables (Imports, Exports, Points) being hidden behind adjacent rows #2409. - Fix iOS QR code in Account settings being cut off on the right side #2406. ## [1.4.0] — 2026-03-22 ### Added - Family page now contains a map with family members markers on it. - Visits page now have "Confirm all" and "Decline all" buttons to quickly confirm or decline all visit suggestions at once. ### Changed - Updated look and feel - The point counting was changed to be more efficient on bigger accounts. - Redesigned raw data archival system for large instances (10M+ points). ### Fixed - Fix Lite plan archival warnings sending all three notifications (11-month, 11.5-month, and 12-month) simultaneously when a user's oldest data already exceeds all thresholds. Now only the most severe warning is sent, and lower thresholds are marked as already notified. - Misconfigured Prometheus settings will no longer litter logs with error messages, it will make multiple attempts to connect instead and then stop. - One of previous versions removed a database index making points upload very slow. The index is now added back to fix the issue. ## [1.3.4] - 2026-03-15 ### Added - Family members can now share their location with each other. In the family settings, you can send a location sharing request to any family member. Once they accept it, you will be able to see their location on the map and they will be able to see yours. You can also revoke location sharing at any time. Location sharing is disabled by default for all existing families, so you need to enable it in the family settings if you want to use this feature. ### Changed - Redesigned onboarding modal with two paths: "I have data" (inline file import) and "Start tracking" (app download + QR code). New users with existing location data can now start importing within 2 clicks of signing up. - Onboarding completion is now persisted server-side (`settings.onboarding_completed`) instead of relying solely on localStorage, preventing the modal from reappearing after browser data clears. - Route opacity data migration now runs as a background job instead of inline during migration, improving deployment reliability for large instances. ### Fixed - Fix admin and supporter tooltip overflowing the page on narrow screens. #1449 - Fix date navigation arrow tooltips overlapping with the navbar on map pages. #2229 #2100 - Fix infinite loading spinner when a trip has no points in its date range. #2293 - Fix Insights monthly digest panels disappearing when switching months. #2305 - Fix suggested visit confirm/decline not removing the visit from the list. #2307 - Fix Stats page reloading when clicking "countries, cities" link. #2270 - Fix map base layer selection not being restored after page reload (Maps v1). #2093 - Fix duplicate country names in stats caused by geocoder returning different spellings. #2044 - Fix total distance display overlapping layer picker when distance is in miles. #2017 - Fix default route opacity displaying as 6000% for new users. #1891 - Fix shared month stats map missing hexagons from the last day of the month. #1934 - Fix Nominatim reverse geocoder producing all places named "Suggested place" instead of actual place names. #2182 - Fix IDL-crossing route segmenter returning inconsistent coordinate types. `unwrapCoordinates` now always returns a uniform array-of-arrays structure. #2038 - Fix a migration taking too long. #2375 - Fix family sharing not including the requesting user's own location. #2153 - The "Destroy" button on the trip page is now orange. #2348 ## [1.3.3] - 2026-03-12 ### Added - Better user management with pagination, search, and filtering in the admin panel. Admins can now easily find and manage users based on email, registration date, and activity status. ### Fixed - Points table now converts speed from m/s to km/h (or mph) using the user's distance unit preference. Previously raw m/s values were displayed with a "km/h" label. #2337 - Digest list API (`GET /api/v1/digests`) now returns distance as a structured object with `meters`, `converted`, and `unit` fields, matching the detail endpoint. Previously it returned raw meters, causing clients to display incorrect values. **Breaking change**: the `distance` field changed from an integer to an object. #2336 - Dead documentation links in v0.26.0 changelog entry now point to the correct URLs. #2344 - Filter out Immich and Photoprism api keys from logs to prevent accidental exposure. #2368 - Fix foreign key violation when deleting users with place_visits referencing visits. - Fix reverse geocoding job failing on points with nil timestamp or lonlat. - Fix unsupported archive format generating Sentry noise instead of a user-friendly notification. - Fix deadlock in reverse geocoding places upsert under concurrent Sidekiq workers. - Reduce Redis disk I/O by relaxing RDB snapshot frequency. Previously the default `save 60 10000` rule caused a snapshot every ~60 seconds due to Sidekiq polling, generating tens of terabytes of disk writes over weeks. New defaults: snapshots every 15 minutes (10+ changes) or 5 minutes (100+ changes). - Reduce default Sidekiq concurrency from 10 to 5 threads. Most self-hosted instances don't need 10 workers and the extra threads increase Redis polling traffic. - Migration bug for version skippers. #2362 ## [1.3.2] - 2026-03-08 **Important**: Self-hosters are not limited in any way. All features remain fully available regardless of plan. The new Lite plan and related limitations apply only to Dawarich Cloud users. If you're self-hosting, you can ignore the Lite plan details below. Self-hosted instances will continue to have access to all features without any restrictions. ### Added - Lite plan for Dawarich Cloud. Lite includes core tracking, map visualization (routes, points), stats, and the read API. Data view is limited to the last 12 months — older data is archived but can always be exported. Pro-only features: Heatmap, Fog of War, Scratch Map, Globe View, Immich/Photoprism integrations, public stats sharing, and write API (update/delete). Lite users can still create points via the API. Self-hosted instances are unaffected — all features remain fully available regardless of plan. - Timed layer previews for Lite users on the map. Toggling a Pro-only layer (Heatmap, Fog of War, Scratch Map) shows it for 20 seconds with a countdown, then auto-hides with an upgrade prompt. - Per-plan API rate limiting via `rack-attack`. Lite: 200 requests/hour, Pro: 1,000 requests/hour. Self-hosted instances are exempt. Rate-limited responses return 429 with `Retry-After` header. - Archival warning notifications for Lite users approaching the 12-month data window: in-app notification at 11 months, email at 11.5 months, archived confirmation at 12 months. - `GET /api/v1/plan` endpoint returning the user's current plan and feature availability. - `X-Total-Points-In-Range` and `X-Scoped-Points` response headers on the points API, allowing clients to detect when data is being windowed. - Branded OAuth buttons for Google and GitHub on the login page. ### Changed - Numeric-only strings passed to timestamp API parameters (e.g. `start_at`, `end_at`) are now treated as Unix timestamps directly. Previously they were passed through `Time.zone.parse`, which could return unexpected results. If you were relying on the old behavior for numeric strings, update your API calls accordingly. - The user serializer now includes `plan` in the `subscription` object. ## [1.3.1] - 2026-02-27 ### Changed - User deletion now being done in the background to prevent request timeouts for users with large amount of data. ### Fixed - Point speed in Map V2 is now correctly calculated from m/s to km/h or mph based on user preference. #2308 - Family members are now being loaded correctly on Map V2 when family layer is enabled. #2250 - Photos popups on Map V2 now show the photo timestamp in user's timezone. #2310 - Fix the issue preventing fresh app from starting. #2304 ## [1.3.0] - 2026-02-25 The Storage & Timeline Interaction Release This release adds a dedicated `motion_data` column for transportation-relevant fields alongside the existing `raw_data`. Users can now set their timezone for accurate date/time display across the app. The Timeline feed in Map v2 gains richer map interaction: hovering a journey highlights its track with an animated border, clicking zooms to fit and selects it, and expanding a day shows visit markers even when the Visits layer is off. User data export/import is enhanced with a new v2 format using JSONL files and monthly splitting for large datasets, while remaining backward-compatible with the old format. ### Added - Per-user timezone setting. Users can now select their timezone from Settings > General, and all dates/times across the app (including background jobs and API responses) will respect it. Defaults to the server's `TIME_ZONE` environment variable for existing users. - `motion_data` JSONB column on the `points` table for storing transportation-relevant fields separately from `raw_data`. - Background job (`DataMigrations::BackfillMotionDataJob`) to backfill `motion_data` from `raw_data` for existing points. - New Timeline feed in Map v2 Tools panel for browsing daily location history. Distances and speeds respect the user's distance unit preference (km/mi). - Clicking a track point (when "Show Points" is enabled) now displays point info (timestamp, battery, altitude, speed) in the track info panel instead of triggering a position update. Dragging a point still updates its position and triggers track recalculation. - Timeline-map interaction: hovering a journey entry in the Timeline feed now highlights the matching track on the map with the animated border and flow effect. Clicking a journey entry zooms the map to fit the track and keeps it selected. Expanding a day in the Timeline now temporarily shows visit markers for that day, even if the Visits layer is disabled. - AES-256-GCM encryption for raw data archives (format version 2). Set `ARCHIVE_ENCRYPTION_KEY` to use a custom key; otherwise derives from `SECRET_KEY_BASE`. Existing unencrypted archives (format version 1) are read transparently. - v2 export/import format with JSONL files and monthly splitting for large entities (points, visits, stats, tracks, digests). The new format streams data to avoid memory issues with large datasets, while remaining backward-compatible with v1 archives (`data.json`). - User data export now includes Tags, Taggings, Tracks (with embedded TrackSegments), Digests, and Raw Data Archives — previously missing from export/import, meaning users who exported and re-imported would lose these entities. - Tracks are exported with their `original_path` serialized as WKT and `track_segments` embedded as a nested array, preserving transportation mode detection data across export/import cycles. - Digests get a fresh `sharing_uuid` on import for security — old share links from the original user won't work for the importing user. - Raw Data Archives are exported with their attached gzip files, enabling full data restoration. - Failed imports now will have an error message shown to the user. - Pagination now looks nicer and more informative, indicating current page. #2279 - Imports and exports now can be sorted by name, file size, number of points, and creation date. #2279 - Lots of missing Swagger specs for the API endpoints have been added, improving API documentation and enabling better client generation. swagger.yaml is updated. ### Changed - Transportation-relevant fields (motion, activity, action) are now stored in a dedicated `motion_data` column alongside `raw_data`, enabling efficient transportation mode detection. - All import sources now write both `raw_data` (full original payload) and `motion_data` (transportation-relevant fields). - The `STORE_GEODATA` setting now correctly controls whether geodata is written during reverse geocoding. - Dropped unused `idx_points_user_city` database index (304 MB) and replaced the full `reverse_geocoded_at` index (1,149 MB) with a smaller partial index covering only un-geocoded rows. - Selecting a track on Map v2 now always dims other tracks, regardless of whether the track has transportation mode segments. - Default map layers for new users changed from Routes + Heatmap to Tracks + Heatmap. Existing users' settings are unaffected. - Renamed the bottom-panel "Timeline" feature to "Replay" to avoid naming collision with the new Timeline feed sidebar. - Default value for `RAILS_ENV` in `docker-compose.yml` is now `production` instead of `development` ### Fixed - Stats queries (daily distance, time of day) now correctly handle timezone conversion without double-converting from UTC. - Timezone validation in stats queries now properly resolves Rails timezone names to IANA identifiers. - Clicking on [Map] on Stats page now correctly respects the user's preferred map version (v1 or v2) instead of always linking to Map v1. #2281 ## [1.2.0] - 2026-02-15 ### Changed - Overall app performance in browser was improved - Docker images are now being built in parallel for both amd64 and arm64 architectures to speed up the build process. Thank you @rtuszik! ### Added - Map v2 requires WebGL support, so if user's browser doesn't support it or it's disabled, they will see a warning message with a link to the list of supported browsers. - New **Insights API** (`GET /api/v1/insights`) returning year overview with totals, activity heatmap, and streak data for the mobile app. - New **Insights Details API** (`GET /api/v1/insights/details`) returning year-over-year comparison and travel patterns for the mobile app. - New **Digests API** (`GET/POST/DELETE /api/v1/digests`) allowing the mobile app to list, view, generate, and delete yearly digests. Digest generation runs asynchronously via Sidekiq and returns `202 Accepted`. Digest detail supports conditional GET (`Last-Modified` / `304 Not Modified`). ### Fixed - Scratch map layer is now working again on Map v2. - Colored routes on Map v2 are now working correctly. Zoom in closer to see colored segments. #2254 - Live mode on Map v2 is now working again. ## [1.1.0] - 2026-02-08 The Timeline Release In Map V2 Tools, user can now enable Timeline tool, which allows to quickly navigate through time and see how their location changed throughout the day. It can also be used to replay a trip by clicking the play button. Timeline tool always spans across 24 hours, but you can change the date by clicking on the date picker. Timeline tool is available only on Map V2. ### Added - Photos are now being clustered on the Map v2 to improve performance and usability when viewing large numbers of photos. - City statistics thresholds are now user-configurable: "Min Minutes in City" and "Max Gap Between Points" sliders in the Map v2 Settings panel. #2207 - New Timeline tool is added to Map V2. It allows user to quickly navigate through time and see how their location changed throughout the day. It can also be used to replay a trip by clicking the play button. ### Fixed - The SSL Security Warning is now working correctly on the Immich and Photoprism integration forms. - Family members and Places layers are now being correctly remembered across page reloads on Map v2. - Immich returning 400. #2222 #2186 - Points info on the Map V2 now shows time in 24h format and includes seconds. #2172 - Digests not being created for years earlier than 2000. #2158 - Tracks on Map V2 are now respecting the date filters correctly. #2196 - Undefined method `.to_sym` for nil in Sidekiq. #2190 - `/api/v1/stats` now works faster. ### Changed - Zooming animation is disabled on Map V2 loading #2219 - Exporting points to GPX and GeoJSON now works better and faster for large numbers of points by processing the export in chunks to reduce memory usage. #2161 ## [1.0.4] - 2026-02-01 ### Fixed - Wrong path helper in the navbar for Settings link. #2215 #2213 ## [1.0.3] - 2026-02-01 ### Fixed - Gemfile being not updated #2210 - Excessive memory usage during visits suggestions job (thanks @nareddyt!) #2119 ### Added - `SMTP_STARTTLS` environment variable to enable STARTTLS for SMTP connections. Disabled by default. ## [1.0.2] - 2026-01-31 The Insights, Transportation Mode Detection and Supporter Verification release Quiet a few big things in this release! It starterted with the idea of adding the Insights page. I experimented with it a bit to see what kinds charts and visualizations we can already have based on the existing data. There were some, but one of the most exciting to me would be the ability to see the Activity Breakdown: now many hours I spent walking, driving and running. Spoiler: I didn't run that much last year :) Anyway, to get that, we needed to have transportation mode detection for tracks. So naturally I went ahead and implemented that as well. Now, not only we can see the activity breakdown, but also, on the Map V2, if you click on a track (Tracks layer should enabled), you will see the transportation modes for it. That's what I wanted for Dawarich for a long time, and I'm happy it's finally here! In the map settings panel, there is now Transportation Mode Detection section, where you can configure speed thresholds for each mode. By default, they are set to reasonable values, but you can tweak them as you wish. Changing the thresholds will recalculate modes for all tracks in the background, which may take a while depending on how many tracks you have. Another thing introduced in this release, is support verification. Almost 150 people have supported us financially on [Ko-fi](https://ko-fi.com/freika), [Patreon](https://www.patreon.com/freika) and [GitHub Sponsors](https://github.com/sponsors/Freika/), and if you're one of them, on the Settings page you can now enter your email and verify your support. Verified supporters will get a special (disableable) badge in the navbar as a token of our appreciation. Thank you so much for supporting Dawarich! Anyway, enjoy the release and don't forget to report any bugs you may find! ### Added - App-level DNS cache with 5 minutes TTL to reduce DNS lookups and improve performance. #2183 - New **Insights page** with comprehensive analytics and visualizations: - **Activity heatmap**: GitHub-style contribution graph showing daily activity throughout the year - **Activity streak**: Track your current streak and longest streak of consecutive active days - **Top visited locations**: See your most frequently visited places for the selected year - **Year comparison**: Compare stats (distance, countries, cities, active days) with previous year - **Activity breakdown**: Visualize your activity distribution by transportation mode - **Monthly digest**: Detailed monthly statistics with travel patterns - **Travel patterns**: Time-of-day and day-of-week activity distribution - **Movement wellness**: Health-related insights based on your movement data - **Location clusters**: Geographic clustering of your visited locations - **Transportation mode detection for tracks**: Tracks are now automatically segmented by transportation mode (walking, cycling, driving, etc.) with configurable speed thresholds in settings. Modes are recalculated when threshold settings change. - **Near real-time track generation**: Tracks are now generated within ~45 seconds of receiving new points (via OwnTracks, Overland, or the Points API) using a Redis-based debouncer. This replaces the previous 4-hour polling cycle for most cases. Daily generation job frequency reduced from every 4 hours to every 12 hours as a fallback. - **Track merging**: Consecutive tracks that belong to the same journey are automatically merged when the gap between them is within the configured time threshold. - Email preferences moved to "General" tab in user settings for better organization. ### Fixed - Remove assets before precompilation to prevent stale assets from being served. #2187 - undefined method 'to_sym' for nil in sidekiq #2190 - `Tracks::BoundaryResolverJob` now uses deterministic exponential backoff instead of random delays, and stops retrying after 5 attempts to avoid infinite rescheduling. - Hanging Sidekiq job #2134 ### Changed - Daily track generation job runs every 12 hours instead of every 4 hours, since real-time generation handles most cases. ## [1.0.1] - 2026-01-24 ### Added - SSL certificate verification can now be disabled for Immich and Photoprism integrations to support self-signed certificates. A prominent security warning is displayed when this option is enabled. #1645 ### Fixed - Photo timestamps from Immich are now correctly parsed as UTC, fixing the double timezone offset bug where times were displayed incorrectly. #1752 - Trip photo grids now update immediately after photos are imported, instead of showing cached/stale results for up to 24 hours. #627 #988 - Immich API responses are now validated for content-type and JSON format before parsing, providing clear diagnostic error messages when the API returns unexpected responses. #698 #1013 #1078 - Response validator logs truncated response bodies (max 1000 chars) when JSON parsing fails, improving debugging capabilities. - GeoJSON formatted points now have correct timestamp parsed from `raw_data['properties']['date']` field. - Reduce number of iterations during cache cleaning to improve performance. - Version in the navbar is now correct. #2154 - Dawarich can now be ran under a non-root user in Docker. #1159 - Fix an error on the Trips page when trip is created but no path is yet calculated. #1426 - Catch an error with invalid response during reverse-geocoding. #1439 - In the Immich integration form there are now required permissions listed: `asset.read` and `asset.view`. #1730 - A doc issue regarding suggesting new visits. #1737 - `ALLOW_EMAIL_PASSWORD_REGISTRATION` and `OIDC_AUTO_REGISTER` env vars are now being respected correctly. #1972 - Fog of War layer on Map V1 now properly re-appears when toggled off and on again without requiring a page refresh. #2039 - User's `points_count` counter cache is now properly updated when creating points via OwnTracks, Overland, and generic Points API. This fixes visit suggestions not working for users using HomeAssistant or similar integrations. #2167 - Removed redundant subscriptions to WS channel. - Live mode is working again on both map V1 and V2. ### Changed - Map V2 is now the default map version for new users. Existing users will keep using Map V1 unless they change it in the settings. - Email preferences moved to dedicated "Emails" tab in user settings for better organization. ### Removed - Tile Usage reporting feature and related prometheus metric have been removed due to low usage. #1876 ## [1.0.0] - 2026-01-20 The 1.0.0 release. Same as in 0.37.3, but with updated version number. We're aiming to provide more stable releases going forward. All the issues that are currently open in Github will be addressed in the upcoming releases. ## [0.37.3] - 2026-01-11 ### Fixed - Routes are now being drawn the very same way on Map V2 as in Map V1. #2132 #2086 #2121 - RailsPulse performance monitoring is now disabled for self-hosted instances. It fixes poor performance on Synology. #2139 #2096 ### Changed - Map V2 points loading is significantly sped up. - Points size on Map V2 was reduced to prevent overlapping. #2122 - Points sent from Owntracks and Overland are now being created synchronously to instantly reflect success or failure of point creation. ## [0.37.2] - 2026-01-04 ### Fixed - Months are now correctly ordered (Jan-Dec) in the year-end digest chart instead of being sorted alphabetically. - Time spent in a country and city is now calculated correctly for the year-end digest email. #2104 - Updated Trix to fix a XSS vulnerability. #2102 - Map v2 UI no longer blocks when Immich/Photoprism integration has a bad URL or is unreachable. Added 10-second timeout to photo API requests and improved error handling to prevent UI freezing during initial load. #2085 ### Added - In Map v2 settings, you can now enable map to be rendered as a globe. ## [0.37.1] - 2025-12-30 ### Fixed - The db migration preventing the app from starting. - Raw data archive verifier now allows having points deleted from the db after archiving. ## [0.37.0] - 2025-12-30 ### Added - In the beginning of the year users will receive a year-end digest email with stats about their tracking activity during the past year. Users can opt out of receiving these emails in User Settings -> Notifications. Emails won't be sent if no email is configured in the SMTP settings or if user has no points tracked during the year. ### Changed - Added and removed some indexes to improve the app performance based on the production usage data. ### Changed - Deleting an import will now be processed in the background to prevent request timeouts for large imports. ### Fixed - Deleting an import will no longer result in negative points count for the user. - Updating stats. #2022 - Validate trip start date to be earlier than end date. #2057 - Fog of war radius slider in map v2 settings is now being respected correctly. #2041 - Applying changes in map v2 settings now works correctly. #2041 - Invalidate stats cache on recalculation and other operations that change stats data. ## [0.36.4] - 2025-12-26 ### Fixed - Fixed a bug preventing the app to start if a composite index on stats table already exists. #2034 #2051 #2046 - New compiled assets will override old ones on app start to prevent serving stale assets. - Number of points in stats should no longer go negative when points are deleted. #2054 - Disable Family::Invitations::CleanupJob no invitations are in the database. #2043 - User can now enable family layer in Maps v2 and center on family members by clicking their emails. #2036 ## [0.36.3] - 2025-12-14 ### Added - Setting `ARCHIVE_RAW_DATA` env var to true will enable monthly raw data archiving for all users. It will look for points older than 2 months with `raw_data` column not empty and create a zip archive containing raw data files for each month. After successful archiving, raw data will be removed from the database to save space. Monthly archiving job is being run every day at 2:00 AM. Default env var value is false. - In map v2, user can now move points when Points layer is enabled. #2024 - In map v2, routes are now being rendered using same logic as in map v1, route-length-wise. #2026 ### Fixed - Cities visited during a trip are now being calculated correctly. #547 #641 #1686 #1976 - Points on the map are now show time in user's timezone. #580 #1035 #1682 - Date range inputs now handle pre-epoch dates gracefully by clamping to valid PostgreSQL integer range. #685 - Redis client now also being configured so that it could connect via unix socket. #1970 - Importing KML files now creates points with correct timestamps. #1988 - Importing KMZ files now works correctly. - Map settings are now being respected in map v2. #2012 ## [0.36.2] - 2025-12-06 The Map v2 release In this release we're introducing Map v2 based on MapLibre GL JS. It brings better performance, smoother interactions and more features in the future. User can select between Map v1 (Leaflet) and Map v2 (MapLibre GL JS) in the Settings -> Map Settings. New map features will be added to Map v2 only. ### Added - User can select between Map v1 (Leaflet) and Map v2 (MapLibre GL JS) in the User Settings. ### Fixed - Heatmap and Fog of War now are moving correctly during map interactions on v2 map. #1798 - Polyline crossing international date line now are rendered correctly on v2 map. #1162 - Place popup tags parsing (MapLibre GL JS compatibility) - Stats calculation should be faster now. ## [0.36.1] - 2025-11-29 ### Fixed - Exporting user data now works a lot faster and consumes less memory. - Fix the restart loop. #1937 #1975 ## [0.36.0] - 2025-11-24 OIDC and KML support release So, you want to configure your OIDC provider. If not — skip to the actual changelog. You're going to need to provide at least 4 environment variables: `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, `OIDC_ISSUER`, and `OIDC_REDIRECT_URI`. Then, if you want to rename the provider from "OpenID Connect" to something else (e.g. "Authentik"), set `OIDC_PROVIDER_NAME` variable as well. If you want to disable email/password registration and allow only OIDC login, set `ALLOW_EMAIL_PASSWORD_REGISTRATION` to `false`. After just 7 brand new environment variables, you'll never have to deal with passwords in Dawarich again! Jokes aside, even though I'm not a fan of bloating the environment with too many variables, this is a nice addition and it will be reused in the cloud version of Dawarich as well. Thanks for waiting more than a year for this feature! To configure your OIDC provider, set the following environment variables: ``` OIDC_CLIENT_ID=client_id_example OIDC_CLIENT_SECRET=client_secret_example OIDC_ISSUER=https://authentik.yourdomain.com/application/o/dawarich/ OIDC_REDIRECT_URI=https://your-dawarich-url.com/users/auth/openid_connect/callback OIDC_AUTO_REGISTER=true # optional, default is false OIDC_PROVIDER_NAME=YourProviderName # optional, default is OpenID Connect ALLOW_EMAIL_PASSWORD_REGISTRATION=false # optional, default is true ``` ### Added - Support for KML file uploads. #350 - Added a commented line in the `docker-compose.yml` file to use an alternative PostGIS image for ARM architecture. - User can now create a place directly from the map and add tags and notes to it. If reverse geocoding is enabled, list of nearby places will be shown as suggestions. - User can create and manage tags for places. - Visits for manually created places are being suggested automatically, just like for areas. - User can enable or disable places layers on the map to show/hide all or just some of their visited places based on tags. - User can define privacy zones around places with specific tags to hide map data within a certain radius. - If user has a place tagged with a tag named "Home" (case insensitive), and this place doesn't have a privacy zone defined, this place will be used as home location for days with no tracked data. #1659 #1575 ### Fixed - The map settings panel is now scrollable - Fixed a bug where family location sharing settings were not being updated correctly. #1940 ### Changed - Internal redis settings updated to implement support for connecting to Redis via unix socket. #1706 - Implemented authentication via GitHub and Google for Dawarich Cloud. - Implemented OpenID Connect authentication for self-hosted Dawarich instances. #66 ## [0.35.1] - 2025-11-09 ### Fixed - StrongMigration issue #1931 ## [0.35.0] - 2025-11-09 ⚠️ Important ⚠️ The default `docker-compose.yml` file has been updated to provide sensible defaults for self-hosted production environments. This should not break existing setups, but it's recommended to review your `docker-compose.yml` file and update it accordingly. You can now set `RAILS_ENV` environment variable to `production` to run Dawarich in production mode. ### Added - Selection tool on the map now can select points that user can delete in bulk. #433 ### Fixed - Taiwan flag is now shown on its own instead of in combination with China flag. - On the registration page and other user forms, if something goes wrong, error messages are now shown to the user. - Leaving family, deleting family and cancelling invitations now prompt confirmation dialog to prevent accidental actions. - Each pending family invitation now also contains a link to share with the invitee. ### Changed - Removed useless system tests and cover map functionality with Playwright e2e tests instead. - S3 storage now can be used in self-hosted instances as well. Set STORAGE_BACKEND environment variable to `s3` and provide `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `AWS_BUCKET` and `AWS_ENDPOINT_URL` environment variables to configure it. - Number of family members on self-hosted instances is no longer limited. #1918 - Export to GPX now adds speed and course to each point if they are available. - `docker-compose.yml` file updated to provide sensible defaults for self-hosted production environment. - `.env.example` file added with default environment variables. - Single Dockerfile introduced so Dawarich could be run in self-hosted mode in production environment. ## [0.34.2] - 2025-10-31 ### Fixed - Fixed a bug in UTM trackable concern. #1909 ## [0.34.1] - 2025-10-30 ### Fixed - Broken Stats page for users with no reverse geocoding enabled. #1877 ### Changed - Date navigation on the map page is no longer shown as floating panel. It is now part of the top navigation bar to prevent overlapping with other map controls. #1894 #1881 ### Added - [Dawarich Cloud] Added support for UTM parameters during user registration. UTM parameters will be stored with the user record for marketing analytics purposes. ## [0.34.0] - 2025-10-10 The Family release In this release we're introducing family features that allow users to create family groups, invite members, and share location data. Family owners can manage members, control sharing settings, and ensure secure access to shared information. Location sharing is optional and can be enabled or disabled by each member individually. Users can join only one family at a time. Location sharing settings can be set to share location for 1, 6, 12, 24 hours or permanently. Family features are now available only for self-hosted instances and will be available in the cloud in the future. When "Family members" layer is enabled on the map, family member markers will be updated in real-time. ### Added - Users can now create family groups and invite members to join. ### Fixed - Sign out button works again. #1844 - Fixed user deletion bug where user could not be deleted due to counter cache on points. - Users always have default distance unit set to kilometers. #1832 - All confirmation dialogs are now showing only once. ### Changed - Minor versions of Dawarich are being built for ARM64 architecture as well again. #1840 - Importing process for Google Maps Timeline exports, GeoJSON and geodata from photos is now significantly faster. - The Map page now features a full-screen map. ## [0.33.1] - 2025-10-07 ### Changed - On the Trip page, instead of list of visited countries, a number of them is being shown. Clicking on it opens a modal with a list of countries visited during the trip. #1731 ### Fixed - `GET /api/v1/stats` endpoint now returns correct 0 instead of null if no points were tracked in the requested period. - User import data now being streamed instead of loaded into memory all at once. This should prevent large imports from exhausting memory or hitting IO limits while reading export archives. - Popup for manual visit creation now looks better in both light and dark modes. #1835 - Fixed a bug where visit circles were not interactive on the map page. #1833 - Fixed a bug with stats sharing settings being not filled. #1826 - Fixed a bug where user could not be deleted due to counter cache on points. #1818 - Introduce apt-get upgrade before installing new packages in the docker image to prevent vulnerabilities. #1793 - Fixed time shift when creating visits manually. #1679 - Provide default map layer if user settings are not set. ## [0.33.0] - 2025-09-29 ### Fixed - Fix a bug where some points from Owntracks were not being processed correctly which prevented import from being created. #1745 - Hexagons for the stats page are now being calculated a lot faster. - Prometheus exporter is now not being started when console is being run. - Stats will now properly reflect countries and cities visited after importing new points. - `GET /api/v1/points` will now return correct latitude and longitude values. #1502 - Deleting an import will now trigger stats recalculation for affected months. #1789 - Importing process should now schedule visits suggestions job a lot faster. - Importing GPX files that start with `