shortn
Docs/Storage

Storage and counting

One key-value namespace and four kinds of key. Knowing the shape is useful when reading the report page or working out why a number looks wrong.

One namespace · four key families · links carry a TTL, counters do not

What is written

<slug>
The link itself: destination, title, note, times, and the password digest in metadata if it is protected. This key carries a TTL.
clicks:*
Visit counts, including the per-day buckets and the referrer, device and country tallies behind the stats page.
meta:*
Service-level counters the stats page reads.
rate:*
The sliding-window counters behind the limits page. They expire on their own.

The clicks:, meta: and rate: families are filtered out of /api/links, /api/stats, /api/export and the sweeper. Only real links appear anywhere a human reads, which is why the listing endpoints return a bare array of links and nothing else.

Expiry is the store's, not a check in the code A link key is written with a TTL rather than having its age compared on every request. Lookup still checks the metadata, so an expired link reads as absent even in the window before the store drops it. That window is why an expired slug can still be deleted on request rather than simply being overwritten.

Two things about the TTL worth knowing

What a click records

A visit is recorded just before the redirect is sent, and only for a link that resolves.

Why the numbers agree

Every figure that depends on a link's age — days remaining, whether it is expired — is computed on the server from when it expires. Nothing is counted down in the browser.

The only arithmetic done client-side is on the rows in your own links table, and those are yours alone, in your browser, from what the server returned. Two people looking at the service-wide numbers cannot see different answers; two people looking at their own list might, if one of them is looking at a stale copy.