Project 2 / 52

Expiry Ledger

A calendar tells you when something happens. This tells you when to start.

Built after my national ID expired without my noticing and my bank accounts were frozen the same day. A private registry for everything with a date attached, sorted by when you have to act, not by when it expires. Try the working demo on this page.

Date
October 2026
Category
Software
Disciplines
Product Design · UX/UI · Front-End Engineering · Data Visualisation
Built with
TypeScript · React · CSS
Live demo

Try it. It’s yours to break.

Add your own dates, renew, delete, export. It runs entirely in your browser, and Reset demo puts everything back.

Expiry Ledger

Working demo
Demo

Opens full screen, like an app. Close it any time to come back here.

Expiry LedgerDemo
Opening the ledger…

About this demo

Why I built it

On 12 July 2026, my national ID expired, and my bank accounts were frozen that same day. I hadn’t realised it was expiring, because I rarely check expiry dates. My renewed ID arrived on 14 July, but it took another week of contacting the banks and verifying the new ID before my accounts were restored. Renewing the ID took two days. The week that followed came from not knowing in time.

The problem

IDs, passports, insurance, domains, subscriptions, warranties. Almost everything important expires, and some expiries reach further than you expect: an expired ID can lock you out of your own bank accounts. A calendar tells you when something happens. It does not tell you when to start acting, or how much is quietly renewing over the next twelve months. So I built the tool I needed: one place for every date that matters, ordered by when to act.

How it decides

  1. 01

    Every item has a lead time

    A domain needs about thirty days of notice. A passport needs two hundred and seventy, because renewals take weeks. Each category starts with a sensible default, and every item can change it.

  2. 02

    Act-by comes first

    The ledger subtracts the lead time from the expiry date and sorts by the result. That is why a passport ten months away can still sit at the top of the list.

  3. 03

    Status in colour and in words

    Expired, Action due, Within 60 days, On track. Colour is reserved for urgency, so red always means something, and every status is also written out so it never relies on colour alone.

  4. 04

    Cost per year, not per bill

    Monthly, weekly and yearly charges are annualised and summed by currency, so the real price of everything you have already signed up for is a single number.

12Categories, each with its own lead time
4Statuses, in colour and in words
0Accounts needed
0Bytes sent anywhere

What the demo does

  • Next action: the single most urgent item, with one-tap renew.
  • The next twelve months as action windows, from the day to start acting to the day it expires.
  • Where the money goes: every scheduled cost annualised and broken down by category.
  • Search, status filters, sorting, and summary tiles that jump straight to what needs attention.
  • Quick add presets, a live preview of the act-by date as you type, and inline validation.
  • Mark renewed advances an item by its own schedule, calendar-aware down to month ends and leap years.
  • Undo for deletes and renewals, calendar export (.ics) for one item or all of them, and JSON import and export.
  • On a phone it opens full screen like an app, with a tab bar, bottom sheets you can swipe away, and a back button that closes them.
  • On a computer it sits in the page with a sidebar, keyboard shortcuts and full keyboard access.

From local tool to live demo

The first version was a private app that ran only on my own machine: a small Python server and a JSON file, with no account and no cloud. For the challenge I audited it, rebuilt it to run entirely in the browser, and moved it into this site's design system so anyone can try it. Along the way it gained the twelve-month view, the spending breakdown, quick add, safer imports, and two renewal fixes: renewing before the expiry date now works, which the original quietly ignored, and a renewal on the 31st stays on the 31st after a short month.

Your data stays with you

The demo starts with sample items and saves your changes only in your own browser's storage. Nothing you type is sent to me or anyone else. Reset demo brings the samples back, and clearing this site's data in your browser removes everything.

Calm by default, loud when it matters.