
Notification buttons without a session
A habit reminder now has Done and Snooze buttons. The service worker that handles them has no access token, by design, so each button carries a signed, single-purpose link instead.
21 posts.
In: Security & Privacy Product Postmortems Engineering Infrastructure Design

A habit reminder now has Done and Snooze buttons. The service worker that handles them has no access token, by design, so each button carries a signed, single-purpose link instead.

Every delete in PaceStreak now offers Undo, backed by a 30-day trash on the server. Why the trash stores generic snapshots, keeps original ids, and refuses a restore that would clash.

The new daily coach is a few if-statements over your own data. Why that beats a generated paragraph, and why the app shows only the notes its existing cards don't already cover.

The API went down behind a Cloudflare Tunnel error and stayed down through a reboot, an interrupted OS upgrade, a stale connection pool, and a box too small for its own workload. None of the four were the same bug.

Three real bugs found by using the OTP flow the way a person actually would: a stuck login, a false 'already registered' error, and a confirmation screen that didn't lead anywhere. Plus a status page that finally watches the whole stack.

Login worked, /me failed, and the browser blamed CORS. The real cause was three layers down: Swarm silently ignoring a short-form tmpfs key, which meant Starlette's outermost error middleware - the one layer that runs before CORS headers exist - was the one answering.

The API's hosting decision is made: a free-tier GCP VM, Neon and Upstash, zero-downtime rolling updates on a single-node Swarm - and why the VM pulls its own updates instead of GitHub Actions pushing them.

Turnstile went on signup, login, forgot-password, resend-verification and recover for one reason: those five endpoints can empty a free email quota or grind past a rate limit, and a CAPTCHA on the feed or the streak grid would only annoy people who never touch them.

recompute() reads a stats row, decides what's new, then writes a fresh one back - with no lock between the read and the write. Two concurrent calls could disagree about what changed, or insert the same badge twice.

A small bar row and a keep-rate percentage on every habit's detail page - kept in lime, missed in flame, because the week strip and calendar markers already meant that, and a new chart is the wrong place to invent a third colour convention.

Picked once at onboarding, read from localStorage ever since - and gone the moment someone switched phones or cleared their browser. It was account state that had been living like a device preference.

Notes on habit days exposed a classic API trap: an idempotent PUT that sets a day's amount would also wipe its note. Pydantic's model_fields_set tells 'not sent' apart from 'sent empty'.

Progress photos used to live only on the phone. Now they can be backed up to the account, opt-in, with the bytes checked, never cached, and deleted everywhere when backup is turned off.

Body data grew from weight and waist to a full tape measure, neck to calf. Everything is stored in centimetres and converted only at display, the same rule as kilograms and metres.

The API's test suite empties the database it points at, including the dev admin account. How we keep it pointed at the right one.

Export as JSON, CSV or calendar; import it back; delete with a 30-day safety net; units that can't corrupt history; and moderation that never touches your training log.

Five features built in one pass: an injury pause that can't be abused, planned rest on the grid, a weekly recap, GPX/FIT/CSV import without third-party sync, a private calendar feed, and an official account nobody can imitate.

How PaceStreak's background worker notices streaks that ended in silence, times reminders to each person's evening, sends a weekly recap, and stays safe to run twice.

Follows with approval, a feed checked for visibility twice, crews that share exactly three things, coach access you control, age gates, and moderation that never touches your training log.

RS256 access tokens held only in memory, rotating refresh tokens with reuse detection, CSRF on cookie transport, TOTP with replay protection, and the gaps we have written down rather than hidden.

Why the session cookie uses __Secure- rather than __Host-, why SameSite=Lax is enough, and the rule it forces on the whole domain.
PaceStreak is a habit and streak tracker for training and everything else worth doing regularly.