All posts

2 min read

Three bugs from building a habit tracker

Quit streaks reversed the meaning of a check-in, an installed app lost its profile, and server-rendered dates landed in 1970.

I built Habitrack to track my habits. When I added quit streaks, I found that the same check-in could mean a completed habit or a slip, depending on what I was tracking.

Two kinds of tracking

A normal habit records days when I did something. Its schedule matters: a day off should not break a streak or count as a miss.

A quit tracker works the other way around. It starts on a chosen date, counts days as clean automatically and stores a check-in only when there is a slip. The same check-in table therefore has opposite meanings depending on the tracker. A row means done for a habit and slipped for a quit.

The Overview and export both initially omitted quit trackers. The export would also have called a slip done. I gave quits their own Overview section and export statuses, then added tests because numbers with the meanings reversed can still look plausible.

Reopening the app

An installed iOS PWA also got stuck bouncing between the app and the profile picker. I first tried refreshing the session cookie on the way home. Logs showed that fix did not run in the affected case. The cookie was already valid; the missing piece was profile data in localStorage. iOS had copied the cookie into the installed app but not localStorage. I removed the ineffective fix and had the server supply the profile identity so the client could restore it.

The date on first paint

Server rendering the habit list exposed a date bug in the Overview. In the Workers runtime, the module-level date was evaluated as 1970. The server rendered zero statistics and heatmap dates in 1969, then the browser corrected them after hydration. The development server did not show the problem because it evaluated the module in Node.

I passed the visitor's date into the server-side calculations and checked the result in the Workers runtime. Neither bug showed up where I was looking. The profile loop only happened in the installed app, and the 1970 date only in the Workers runtime, never in the dev server.

Try it

The demo needs no login. The source is on GitHub.

Keyboard shortcuts

/
Search
ga
About
gp
Projects
gb
Blog
ge
Experience
gc
Contact
help
Terminal commands in search
t
Switch theme
?
This panel
Esc
Close or clear