Devlog — 2026-08-31#

TL;DR#

Goals shipped: the Goals tab is now live for all Android release users, with a wave of matched polish landing on mobile and webapp together — countdown badges on horizon cards, a last-day-of-period nudge, and period notes replacing the old goal-review-note field everywhere. Recurring tasks can now repeat every N weeks, months, or years, not just days. The webapp got a task-card consistency pass across board, timer, and a new Daily Toad picker (now reachable from anywhere, scrollable, filterable), plus a period jumper for the goal timeline and a round of dashboard/nav cleanup. Reminders and the daily summary now fire at 9am in the user’s own timezone instead of server UTC. On the backend: another refresh-token edge case chased down, a sync scope-dedup fix, and stale devices no longer eating push notifications meant for someone still there. Release 1.11.0.

User-facing features#

  • Goals tab shipped to Android release users — the build-time flags gating it were removed outright rather than flipped for release, since both features were already gated at runtime where it mattered and iOS never had the flags in the first place.
  • Goal timeline polish landed on mobile and webapp together: a countdown badge on each horizon card showing days left in the period, colour-graded by how much of it has elapsed (calm under 60%, warning to 85%, red after), and a dashboard nudge card that appears on the final day of a period with a goal set. Webapp copy says “wrap up” rather than “review,” since the period hasn’t ended yet — mobile’s card is dismissible per device, webapp’s isn’t, since there’s no synced dismissal state to read.
  • Recurring tasks can repeat every N weeks, months, or years now, not just days — the picker gained a unit selector, and month/year math clamps day-of-month the same way on both the app and the backend so a rule set on the 31st doesn’t quietly roll into the wrong month.
  • Period notes replace the old goal-review-note field everywhere: mobile’s review screen never actually had a text input for it, and the webapp’s version only appeared on an ended, unreviewed goal, then locked. The new note block is tap-to-edit and reachable regardless of period state, on both platforms — old review notes were migrated into the new field before the column was dropped.
  • Task cards now look and behave the same across the webapp — board, timer panel, and the new toad picker all render from the same two shared pieces instead of each surface having its own stripe width, dot colour, and shade of grey. Mobile task cards also gained an activity badge, matching the webapp’s layout.
  • Daily Toad: the picker sheet is reachable from any page now (previously only from Goals), and it’s scrollable and filterable — before this, a user with no toad set had nowhere to even discover the feature.
  • Goal timeline gained a period picker — jump straight to any period via dropdown instead of clicking prev/next dozens of times to reach, say, this year’s Q1.
  • Reminders and the daily summary email now resolve 9am in the user’s own timezone instead of server UTC — a UTC+2 user was getting pinged at 11am, a UTC-5 user at 4am.
  • Fixed a bug where queuing a second task-undo while the first snackbar was still on screen silently broke every future undo snackbar until you left and returned to the Tasks screen.

Technical improvements#

  • Refresh-token rotation, still the ongoing theme: a request that lands after another caller already rotated proactively was reading its own 401 as a dead refresh token and rotating a second time, orphaning a token in the chain. Now it compares against what’s actually stored and only rotates on a genuine mismatch.
  • Sync: a force-sync batch containing both a period note and a goal change — which map to the same underlying table — was emitting the sync scope twice; now deduped, and an empty scope no longer tells other devices to sync nothing for no reason.
  • Push notifications: devices with no live session (gone quiet, but not yet reclaimed by the 30-day stale cleanup) were still eligible for every push fan-out — four idle devices had absorbed all 314 pushes in one observation window. They’re now excluded until they re-authenticate.
  • Webapp cleanup: 49 unreferenced CSS classes removed (checked by hand first for any dynamic class-name construction that a grep would miss), alongside a round of dashboard fixes — task cards were clipping their own content, the Today card listed every open task instead of just due/overdue, primary nav overflowed on smaller screens, and the timer page’s settings form was a stale duplicate that silently ignored saves.
  • Version 1.11.0 released.