DoorFlow Desktop release notes
1.14.14
Changed
- Minor user-interface tweaks.
1.14.12
Fixed
- Windows update prompt now shows the version, not a build number. WinSparkle's "you have X" line read a build number (e.g. "you have 51") because the app reported its build number in WinSparkle's display slot. It now sets the display version (
win_sparkle_set_app_details) to the marketing version (e.g.1.14.11) and the comparison version (win_sparkle_set_app_build_version) to the build number separately, matching how the appcast carriesshortVersionString(display) vsversion(compare). Takes effect only once a user is running a build containing this change - installs already in the field keep showing their build number until they update. - A people sync of a large account no longer aborts on a single network blip. A big account is fetched a page at a time (~50 people per page, so ~130 pages for 6,400 people); previously any failed page - most often a transient timeout or dropped connection on a busy/proxied network - abandoned the entire run and discarded all progress, which is why a sync would repeatedly "fail after around 600." Each page is now retried up to 4 times with backoff (2/4/8/16s) before the sync gives up, and the retry budget resets on every successful page, so a network that blips once per page can still complete.
- A garbled response, or one bad person record, no longer kills the whole sync. A page that comes back unparseable (e.g. a proxy returning an HTML error page with a
200status) is now retried like any other transient page failure instead of failing the sync outright; and a single malformed person record inside an otherwise-valid page is skipped and logged rather than abandoning the remaining thousands.
Changed
- The card preview no longer re-decodes the photo from disk on every repaint. During a live window resize the preview repaints continuously, and each paint was re-reading and re-decoding the person's photo from disk. The decoded image is now memoised on the person (reloaded if the photo URL changes), so a burst of repaints costs one decode instead of dozens.
- Photos now download in parallel instead of one-at-a-time. The photo cache used to fetch every person's images sequentially with a blocking request each - tens of minutes for a large account. It now runs up to 5 downloads concurrently on the main event loop (no background thread), which cuts a big account's first photo sync from tens of minutes to a few, while staying polite enough not to trip an image host's rate-limiting. A stall watchdog aborts a pass only if nothing completes for 60s, so a wedged network can't block future passes.
- The people and printed-cards lists are snappier on large accounts. They now render at most the first 200 people / 500 printed cards instead of building a row for every record (thousands of rows was the dominant cost of opening a list, and nobody scrolls that far). Search is unchanged and still runs against everyone - this only limits how many rows are drawn, so anyone is still found by typing a name/email. When a list is capped, the search box placeholder shows a "Showing first N - type to search all" hint. Selection and card actions operate on the displayed rows as before. (Also fixed an O(n²) array-growth pattern in all three list builders.)
- Large-account syncs are substantially faster. Each page of people is now written to the local database in a single transaction instead of one disk commit per person - roughly 50× fewer commits per page - which was the dominant cost of a slow sync on a big account. (Internally this required making the database's transactions reentrant, using SQLite savepoints, so a single failing record rolls back just itself rather than the whole page.)
- Photo caching now downloads the most-recently-updated people first. The cache pass is ordered by
updated_at(newest first) instead of alphabetically, so freshly-changed and just-added people get their photos before an older backlog - meaning an interrupted or throttled pass still caches the faces a front-desk operator is most likely to need now. - Photo caching stops hammering an image host that is refusing requests. When a run of image downloads fails back-to-back (an expired signing scheme, or a corporate proxy/firewall returning
403), the cache pass now stops early instead of re-attempting the whole failing set (hundreds of images) on every pass, indefinitely, while competing with the people sync. It retries again on the next sync. Any successful download resets the counter, so a few individually-stale URLs don't trip it.
1.14.11
Fixed
- A people sync of a large account no longer aborts on a single network blip. A big account is fetched a page at a time (~50 people per page, so ~130 pages for 6,400 people); previously any failed page - most often a transient timeout or dropped connection on a busy/proxied network - abandoned the entire run and discarded all progress, which is why a sync would repeatedly "fail after around 600." Each page is now retried up to 4 times with backoff (2/4/8/16s) before the sync gives up, and the retry budget resets on every successful page, so a network that blips once per page can still complete.
- A garbled response, or one bad person record, no longer kills the whole sync. A page that comes back unparseable (e.g. a proxy returning an HTML error page with a
200status) is now retried like any other transient page failure instead of failing the sync outright; and a single malformed person record inside an otherwise-valid page is skipped and logged rather than abandoning the remaining thousands.
Changed
- The people and printed-cards lists are snappier on large accounts. They now render at most the first 200 people / 500 printed cards instead of building a row for every record (thousands of rows was the dominant cost of opening a list, and nobody scrolls that far). Search is unchanged and still runs against everyone - this only limits how many rows are drawn, so anyone is still found by typing a name/email. When a list is capped, the search box placeholder shows a "Showing first N - type to search all" hint. Selection and card actions operate on the displayed rows as before. (Also fixed an O(n²) array-growth pattern in all three list builders.)
- Large-account syncs are substantially faster. Each page of people is now written to the local database in a single transaction instead of one disk commit per person - roughly 50× fewer commits per page - which was the dominant cost of a slow sync on a big account. (Internally this required making the database's transactions reentrant, using SQLite savepoints, so a single failing record rolls back just itself rather than the whole page.)
- Photo caching now downloads the most-recently-updated people first. The cache pass is ordered by
updated_at(newest first) instead of alphabetically, so freshly-changed and just-added people get their photos before an older backlog - meaning an interrupted or throttled pass still caches the faces a front-desk operator is most likely to need now. - Photo caching stops hammering an image host that is refusing requests. When a run of image downloads fails back-to-back (an expired signing scheme, or a corporate proxy/firewall returning
403), the cache pass now stops early instead of re-attempting the whole failing set (hundreds of images) on every pass, indefinitely, while competing with the people sync. It retries again on the next sync. Any successful download resets the counter, so a few individually-stale URLs don't trip it.
1.14.9
Fixed
- A people sync of a large account no longer aborts on a single network blip. A big account is fetched a page at a time (~50 people per page, so ~130 pages for 6,400 people); previously any failed page - most often a transient timeout or dropped connection on a busy/proxied network - abandoned the entire run and discarded all progress, which is why a sync would repeatedly "fail after around 600." Each page is now retried up to 4 times with backoff (2/4/8/16s) before the sync gives up, and the retry budget resets on every successful page, so a network that blips once per page can still complete.
- A garbled response, or one bad person record, no longer kills the whole sync. A page that comes back unparseable (e.g. a proxy returning an HTML error page with a
200status) is now retried like any other transient page failure instead of failing the sync outright; and a single malformed person record inside an otherwise-valid page is skipped and logged rather than abandoning the remaining thousands.
Changed
- The people and printed-cards lists are snappier on large accounts. They now render at most the first 200 people / 500 printed cards instead of building a row for every record (thousands of rows was the dominant cost of opening a list, and nobody scrolls that far). Search is unchanged and still runs against everyone - this only limits how many rows are drawn, so anyone is still found by typing a name/email. When a list is capped, the search box placeholder shows a "Showing first N - type to search all" hint. Selection and card actions operate on the displayed rows as before. (Also fixed an O(n²) array-growth pattern in all three list builders.)
- Large-account syncs are substantially faster. Each page of people is now written to the local database in a single transaction instead of one disk commit per person - roughly 50× fewer commits per page - which was the dominant cost of a slow sync on a big account. (Internally this required making the database's transactions reentrant, using SQLite savepoints, so a single failing record rolls back just itself rather than the whole page.)
- Photo caching now downloads the most-recently-updated people first. The cache pass is ordered by
updated_at(newest first) instead of alphabetically, so freshly-changed and just-added people get their photos before an older backlog - meaning an interrupted or throttled pass still caches the faces a front-desk operator is most likely to need now. - Photo caching stops hammering an image host that is refusing requests. When a run of image downloads fails back-to-back (an expired signing scheme, or a corporate proxy/firewall returning
403), the cache pass now stops early instead of re-attempting the whole failing set (hundreds of images) on every pass, indefinitely, while competing with the people sync. It retries again on the next sync. Any successful download resets the counter, so a few individually-stale URLs don't trip it.
1.12.2
Security
- The support factory reset (hold Option/Alt on the lock screen) now also clears the cached person photos and template-background images, not just tokens, prefs, and the database. Previously a reset performed to move a machine to a different DoorFlow account left the previous account's face photos on disk. The image folders are recreated empty on the next launch.
Fixed
- Exporting diagnostics as a
.zipfailed on Windows because the shell timed out during PowerShell's cold start (before the tiny archive was written). The shell timeout is now generous enough for PowerShell to run; the command was hardened (powershell.exe -ExecutionPolicy Bypass, success judged by whether the archive actually exists rather than PowerShell's unreliable exit code); and if zipping still fails it falls back to a plain.txtso the export always produces a file. - Windows: the "Template:" caption above the card preview no longer shows an opaque white box. It was a label layered over the preview canvas, and a transparent label over a canvas doesn't render transparently on Windows - so it's now drawn directly onto the canvas instead.
1.12.1
Security
- The support factory reset (hold Option/Alt on the lock screen) now also clears the cached person photos and template-background images, not just tokens, prefs, and the database. Previously a reset performed to move a machine to a different DoorFlow account left the previous account's face photos on disk. The image folders are recreated empty on the next launch.
Fixed
- Exporting diagnostics as a
.zipfailed on Windows because the shell timed out during PowerShell's cold start (before the tiny archive was written). The shell timeout is now generous enough for PowerShell to run; the command was hardened (powershell.exe -ExecutionPolicy Bypass, success judged by whether the archive actually exists rather than PowerShell's unreliable exit code); and if zipping still fails it falls back to a plain.txtso the export always produces a file. - Windows: the "Template:" caption above the card preview no longer shows an opaque white box. It was a label layered over the preview canvas, and a transparent label over a canvas doesn't render transparently on Windows - so it's now drawn directly onto the canvas instead.
1.11.2
Added
- Connection Doctor (Window menu) - a live checker that actively probes and shows, with green/red status, whether the app can reach the Internet, the DoorFlow service, and the photo (image) store, plus whether you're signed in and when people last synced. It calls out the exact fix in plain English - most usefully, it distinguishes "DoorFlow reachable but the photo host is blocked" (a firewall/proxy problem that lets names and job titles through but stops photos downloading) from being offline or signed out. It updates on its own if connectivity changes while it's open (e.g. the internet comes back), and has Sign In Again, Export Diagnostics…, and Re-check buttons.
- Export Diagnostics (a button in the Connection Doctor) opens a Save dialog and writes a redacted diagnostic snapshot the customer can email to support, saved as a
.zip(which is opaque to content-inspection email gateways, so the attachment - full of names, emails and token-shaped strings - isn't flagged or stripped in transit); the saved file is then revealed in Finder/Explorer so it's easy to find. It's named after the app with a timestamp (e.g.DoorFlow-Desktop-Diagnostics-2026-08-03-1430.zip). It records the app version + executable path, sign-in state and key event timestamps (token issue/expiry, last sync, last API error), device clock/skew (a clock well off real time can break sign-in), Internet / API-host / image-host reachability, local-data health that separates the two real failure modes for missing photos/job titles (photo URL present but not yet cached = a photo-download/network problem, versus no photo URL or job title at all = a data problem), and a Recent activity log of the session's key events (sync phases, API errors, sign-in changes, and photo-download failures with their HTTP status - the usual smoking gun). Tokens are redacted. - Activity log - the app now keeps an in-memory log of the session's important events (app start, sign-in changes, sync phases and failures, API errors, and photo-download outcomes including the HTTP status of any that fail). It costs nothing on the running app (memory only, no disk writes) and is included in an Export Diagnostics file, so a "sync failed" can be traced to exactly what went wrong.
- About DoorFlow Desktop window showing the app name, the built version (marketing version + build number), the environment/channel, and copyright. It's reached from the Application menu on macOS ("About DoorFlow Desktop"), from both the card-printing and Front Desk menu bars.
Changed
- Signing in now always shows the DoorFlow login screen instead of silently reusing an existing browser session, so you can choose which account to sign in with (and aren't quietly returned to the wrong one).
- A failed sync now explains what went wrong instead of a bare "Sync failed": "No internet connection - can't sync" when offline, "Can't reach DoorFlow - check your connection" when the service is unreachable, or "Sync couldn't complete - some information may be out of date" otherwise. ("Sync failed" read like an app fault when the usual cause is simply no connection.)
- Check for Updates… has moved from the Help menu into the Application menu (macOS), next to About. The Help menu (which only held that one item) has been removed from both menu bars.
- Template editor - dragging a field from the fields picker onto the card is smoother: (1) a plain click now only selects the field - the drag begins only once you actually move the pointer (a small threshold), rather than on selection; (2) the drag shows a clean translucent (~25% white) "ghost" of the field at its real drop size and corner radius, with the field name centred in uppercase (not bold); (3) the field is grabbed and dropped centred on the pointer instead of snapping its top-left to the cursor; and (4) the previewed and dropped objects come from one shared default-object definition (which also fixes the barcode field's size differing between drag and drop). (Drag images render at @1× even on HiDPI - a Xojo framework limitation - so the ghost can look slightly soft on Retina.)
Security
- The app now refuses a sign-in with a different DoorFlow account than the one it's already set up for, so one account's local people, photos and job titles can't mix with - or leak to - another account on the same computer. (Proper account switching is planned.)
- Builds now carry a 6-month expiry (build date + 6 months, stamped at build time). Once a shipped build passes its expiry it stops working and shows an "out of date" screen directing the user to updates.doorflow.com to download the latest version - a safety net so very old, potentially-insecure builds don't stay in service indefinitely. Debug/IDE runs are never affected, and a mis-stamped/blank expiry fails open (never blocks).
Fixed
- Cancelling or closing the sign-in window on macOS no longer shows a raw system error (e.g. "…WebAuthenticationSession error 1."). Cancelling is now silent, and a genuine sign-in problem shows a plain "Sign-in didn't complete. Please try again."
- When you're not signed in, the bottom-left status now shows a short, clickable "Sign in…" link that starts sign-in, instead of a longer message that could crop unreadably in the fixed-width status area (seen on Windows).
- The card-printing window's title bar showed the old "DoorFlow CardPrint" name; it now reads "DoorFlow Desktop".
- Person photos now update correctly when someone's photo changes in DoorFlow. Previously a changed photo could be missed (the app only checked whether a file was cached, not whether it matched the current photo), and a re-download left the old image behind as an orphaned file. The photo cache now re-downloads when the photo URL changes, deletes the superseded file, records which URL each cached file corresponds to (so it stops re-checking the same people every sync), and refreshes the on-screen photo. Two people who happen to share an identical photo (e.g. the same company logo) no longer overwrite each other's cached image - local photo files are now namespaced per person. The diagnostics photo-cache summary now reports people-to-check / downloaded / already-on-disk / failed.
- Template editor: a background sync completing while you were editing a template no longer snaps the editor palette back to its first (Settings) tab. The tab you're on is now read from the live tab state rather than a variable that only updated when navigating via code - so clicking the Fields/Info tab directly is remembered, and the post-sync template reload restores it correctly.
- Windows auto-updater no longer offers the version you already have as if it were a newer update. It now compares the running build against the appcast's build number (how the feed is published) rather than the marketing version string, so an up-to-date install correctly reports no update available.
- The app now always renders in a light appearance instead of following the system dark-mode setting. On a dark-mode Windows machine the UI (most visibly the Front Desk terminal) had gone almost entirely dark and hard to read, because pure-white backgrounds and pure-black text auto-swap to the system's dark colours when dark-mode support is on. Dark-mode support is now off app-wide (
Supports Dark Modebuild setting), giving a consistent light UI on both platforms.
1.9.14
Fixed
- Searching a people/cards list that matches no-one no longer strands you: previously an empty result switched to the empty-state panel, which hid the search field so you couldn't edit or clear your search. A search that returns nothing now keeps the list panel (and the search field) visible, and the card preview shows a friendly "no-one selected" empty state (the same copy as the full empty page) instead of the previously-selected person's card, with the Template chooser hidden. The full empty-state panel only shows when the view is genuinely empty (no active search).
- Person photo on the card preview no longer shifts/crops incorrectly (appearing pushed to the left, and moving as you resize the window). The photo's crop was being computed from the on-screen frame size instead of the photo's own pixels, so it drifted with the canvas scale and varied by photo; it's now a stable centred cover-fit. This also makes the printed-card photo framing consistent.
- Incremental (2-minute) sync is now anchored to the DoorFlow server's clock from the moment the app launches, closing a window where a device whose clock ran fast could ask the server for changes "since" a time in the future and silently skip recently-updated people. The server-time offset is now measured from the reachability probe (so it's known on launch and refreshed every minute) and remembered between launches, instead of resetting until the first data sync of the session.
Added
- Template editor: colours (text / border / fill) are now chosen with a built-in colour picker (saturation/value square, hue strip, hex entry, a brightness slider flanked by white/black shortcut swatches) that opens next to the colour square and updates the field and card live as you drag - replacing the modal system picker that only applied the colour after you closed it.
Fixed
- Template editor: an object snapped to a centre guide (the card centre or another object's centre) now sits exactly under the guide line - the line is drawn through the object's rendered centre, removing the ~1px gap that pixel-rounding otherwise left.
- Template editor: alignment guides no longer flicker between two positions when you hold an object near a snap point - the snap now sticks to its chosen target instead of flipping between near-tied candidates.
- Completing first-run setup now reliably sticks on macOS. CFPreferences batches its disk flush and could drop the completion flag if you quit soon after finishing, restarting the whole wizard; the flag is now also backed by a small marker file that persists immediately, and the marker is retired once the native setting confirms.
- First-run setup is now marked complete as soon as you sign in (rather than only on the final "Open DoorFlow Desktop" button), so quitting during or right after the initial sync no longer restarts the whole first-run wizard on the next launch.
- Deleting the template you're editing now moves the editor to the next remaining template (instead of leaving the deleted design on the canvas); if no templates remain, it drops to the All People view.
- Creating a new card template no longer opens to a blank card - a new template is given a valid default orientation, so it renders immediately instead of only after toggling the front/back orientation.
1.9.12
Added
- Template editor: colours (text / border / fill) are now chosen with a built-in colour picker (saturation/value square, hue strip, hex entry, a brightness slider flanked by white/black shortcut swatches) that opens next to the colour square and updates the field and card live as you drag - replacing the modal system picker that only applied the colour after you closed it.
Fixed
- Template editor: an object snapped to a centre guide (the card centre or another object's centre) now sits exactly under the guide line - the line is drawn through the object's rendered centre, removing the ~1px gap that pixel-rounding otherwise left.
- Template editor: alignment guides no longer flicker between two positions when you hold an object near a snap point - the snap now sticks to its chosen target instead of flipping between near-tied candidates.
- Completing first-run setup now reliably sticks on macOS.
- First-run setup is now marked complete as soon as you sign in (rather than only on the final "Open DoorFlow Desktop" button), so quitting during or right after the initial sync no longer restarts the whole first-run wizard on the next launch.
- Deleting the template you're editing now moves the editor to the next remaining template (instead of leaving the deleted design on the canvas); if no templates remain, it drops to the All People view.
- Creating a new card template no longer opens to a blank card - a new template is given a valid default orientation, so it renders immediately instead of only after toggling the front/back orientation.
1.9.10
Fixed
- Relaunching now reopens all the dashboard windows you had open, each at its saved size, position and view context (the selected list/group or the template that was being edited, and the selected person) - previously only a single window was restored, with no context.
- If you relaunch with fewer screens than when you saved, windows that no longer fit are gathered onto the main screen, neatly cascaded (rather than being dropped).
- The application-lock password window now appears centred on the same display as the dashboard window you were using, instead of at a fixed position.
- Template editor: switching between templates no longer snaps the edit palette back to the SETTINGS tab - it stays on the tab you were using (the palette still reloads for the newly selected template).
- Card readers are no longer mis-detected as card printers. An HID Global OMNIKEY reader was matching the "HID" card-printer family (which exists to catch HID Fargo printers); reader product lines (OMNIKEY, iCLASS, prox, Signo) are now excluded on both macOS and Windows.
- Template editor: alignment guides now line up exactly with a field's right and bottom edges (they previously drifted ~1px because the object's far edges and the guide were rounded differently); object edges also render pixel-consistent regardless of position.
- Template editor: a selected field's resize handles now sit exactly on the corners/edges (previously biased ~½px, most visible on the right and bottom) and draw on top of the field's bounding box instead of being painted over by it.
Changed
- Centre- and right-aligned card text now word-wraps to fit the field with each line individually aligned, instead of drifting off to one side when the content is wider than a narrow field.
- Card field values are trimmed of stray leading/trailing whitespace before rendering, so a trailing space in data (e.g. a job title) no longer throws off centre/right alignment.
Added
- Lock Application menu item (next to Sign In / Sign Out) to lock the app on demand - the same lock as the inactivity policy. Enabled once a lock password has been set.
- Template editor: fields now have a vertical text alignment control (top / centre / bottom) alongside the existing horizontal alignment; existing fields keep their current bottom placement.
- Template editor: a selected field's corner and edge handles can now be dragged to resize/reshape it (corners resize both axes, edge handles one), with hover cursors and live alignment guides that snap a field's edge or centre to nearby fields - to the card's own centre lines, and to a 30-unit safe margin inside each card edge - as you drag or resize.
- Application lock: the app now prompts for the password set during first-run - on launch (before the main window is drawn, so there's no flash of the UI), and again when you return to it after 5 minutes away. While locked, all other windows are hidden and then restored to their exact positions on unlock; the lock blocks the interface only, so background sync and printing keep running.
1.9.9
Added
- My Account row in the menu showing the signed-in account name (display-only for now).
Changed
- Sign In and Sign Out are now a single menu item that reflects the current state.
- A person with cards in the print queue is now marked with a "Queued" label in the people list (matching the print queue) instead of an easy-to-miss printer icon.
- Offline mode (for testing) is now enforced across sync, template push, time-drift, IP discovery and all API calls; the network state is logged clearly (
NETWORK OFFLINE/ONLINE). Seedocs/offline-behaviour.md. - When offline, network-only menu items (Sign In, Sign Out, Sync Now) are disabled, and the "Open in DoorFlow" card link shows OFFLINE in its rollover.
Fixed
- A token revoked or invalidated server-side now signs the app out (menu returns to "Sign In", re-auth required) instead of appearing to stay signed in. A refresh that fails only because the app is offline no longer signs you out.
- Template-editor fields no longer nudge out of place when clicked to select them - selecting and dragging are now separate gestures (click to select, then click-drag to move).
- Status labels in the people / print lists (e.g. "Queued") are now legible on a highlighted row (previously low-contrast on the selection).
Security
- Sign-in, token refresh, revoke and introspection now authenticate with PKCE and the public client ID only, so no secret ships in the binary.
1.9.8
Added
- My Account row in the menu showing the signed-in account name (display-only for now).
Changed
- Sign In and Sign Out are now a single menu item that reflects the current state.
- A person with cards in the print queue is now marked with a "Queued" label in the people list (matching the print queue) instead of an easy-to-miss printer icon.
- Offline mode is now enforced across sync, template push, time-drift, IP discovery and all API calls; the network state is logged clearly (
NETWORK OFFLINE/ONLINE). Seedocs/offline-behaviour.md. - When offline, network-only menu items (Sign In, Sign Out, Sync Now) are disabled, and the "Open in DoorFlow" card link shows OFFLINE in its rollover.
Fixed
- A token revoked or invalidated server-side now signs the app out (menu returns to "Sign In", re-auth required) instead of appearing to stay signed in. A refresh that fails only because the app is offline no longer signs you out.
- Template-editor fields no longer nudge out of place when clicked to select them - selecting and dragging are now separate gestures (click to select, then click-drag to move).
- Status labels in the people / print lists (e.g. "Queued") are now legible on a highlighted row (previously low-contrast on the selection).
Security
- Sign-in, token refresh, revoke and introspection now authenticate with PKCE and the public client ID only, so no secret ships in the binary.
1.9.3
- The Windows installer is now code-signed with a trusted certificate, so it installs without the "unrecognised app" warning.
- A published SHA-256 checksum lets you verify the download is genuine and untampered.
1.9.2
- Signed with a Developer ID certificate and notarised by Apple, so macOS installs cleanly with no Gatekeeper warnings.
- Universal build that runs natively on both Apple Silicon and Intel Macs.
- Hardened runtime with a stapled notarisation ticket, so it verifies even when offline.