Metro is a read-only dashboard for Metropolitan Police stop and search statistics. Here's how the data flows from the Police API to your screen, and the design decisions behind the way it's cached.
All data comes from the public data.police.uk API, specifically the Met's stop-and-search records. Metro fetches the full available history, not a rolling window, so older months stay comparable to recent ones.
A weekly worker fetches every month, then precomputes one aggregate row per month × age range × type combination and stores only those in the SQLite cache. The dashboard reads those precomputed aggregates, so filtering is a fast indexed lookup, not a scan of raw records. The slow path (ingestion) is fully separated from the fast path (reads).
This app never writes to the cache. It only reads and combines the precomputed rows for the filters you choose — month, age range, and search type. The URL stays in sync with your filters, so any view is shareable.
The first version of this dashboard ran a self-hosted MongoDB — an always-on server process with auth to manage, for a dataset that's really just a few hundred precomputed rows, rewritten wholesale once a week by a single writer and read by one app.
Replace it with SQLite (via Drizzle for typed queries): a single file in a Docker volume, in WAL mode so the rare weekly write never blocks concurrent reads. No server process to run, no port to expose, no auth to manage.
No DB daemon, near-zero idle memory, and a stronger security posture than v1 — nothing listens on the network for the data layer at all. Reads are pre-computed lookups, not scans of raw records.