(Re)Building hub.stx.pub
TL;DR: check out https://hub.stx.pub/, check out the code, submit feature requests etc (PRs welcome!)
📜 Context
I launched hub.stx.pub roughly two years ago. It used sqlite for storage, API endpoints built with go-chi, static vanilla HTML + Alpine.js for talking to the API, Bulma CSS for styling. Fairly straightforward.
With tsatu.rocks I had tasted my new full-stack on a non-trivial project, and I was itching to try it in other places.
So I embarked on a full-rewrite. Like with tsatu.rocks, the goal was both to get more reps in with coding agents, and also to streamline the code from 3 separate repos into a single unified repo.
I had an initial version done a while back, but then life happened and I let it linger. Today I finally cleaned things up and published it! AI tools I used for this project:
- codex for initial implementation
- Zed w/ Gemini 3 Pro for iterative tweaks
- Gemini CLI for some refactoring
- opencode (w/ Gemini 3 Pro) for adding some features, getting repo publish ready
Because this project relies on a running Stacks node, local development wasn't an easy option. Being able to SSH in to my node, fire up codex / opencode within zellij was very powerful and convenient!
📊 Block visualization
The original version used graphviz (rendered in the browser using HPCC's wasm package). Then sometime last year I came across D2 and it looked very promising! Modern, actively developed / maintained, multiple layout engines, official WASM support and more.
Sadly after spending far too much time tinkering with D2 styles, I had to give up 😩 I just couldn't get the visualization to look as compact and yet legible as the original Graphviz version.
There were multiple other detours along the way, including exploring native pan/zoom support for the SVG canvas. But I found the pan/zoom had limited utility and considerable performance impact, so I disabled it (can be enabled in the code by a flag).
Eventually I came crawling back to Graphviz, with some minor improvements in the layout. Pretty happy with how it looks, and I have a few other tweaks I want to make.
⚡ Backend Performance
This application can be pretty I/O heavy: there are some pretty gnarly queries, against some very large sqlite databases (10s-100s of GB). So backend performance had always been a priority.
The previous implementation already had a bunch of tricks to improve performance: storing materialized views of relevant data, caching stuff in-memory (like the mapping of miners' STX to BTC address mapping) etc.
I streamlined the materialized views further, simplifying the DB schema in the process. The DB has WAL mode enabled and I periodically prune old snapshots so the DB doesn't grow unbounded.
One magical moment was when I pointed the agent (IIRC it was codex) to the API endpoint, said it was slow and asked it to speed things up. It analyzed the code, identified the SQL query that was the bottleneck, suggested an index to speed it up, benchmarked the impact (I think the query went down from ~4s down to few 10s of milliseconds!) and rolled out the changes.
🛍️ Misc Notes
- I use Croner to schedule periodic tasks (like updating the snapshot)
- I/O heavy tasks are spawned in their own worker threads so as to not block the main thread (which handles the HTTP requests)
- I use Bun's native sqlite driver as well as the built-in HTTP server for the API endpoints, no 3rd party deps
- Used recharts for the blocks page. Previous implementation used chartjs, which admittedly, did feel snappier. React does add some lag, there's just no getting around it.