version 3, all of it

September 11, 2026 devlogfediversego

version 3, all of it

Version 3 had a map with four directions on it: the blog gets read, the site becomes a place, the system watches itself, and the whole thing gets quietly permanent. The first small wave shipped last week. This is everything else, eight changes, landed together.

The blog gets read. You can now subscribe by email, either every post or a weekly digest, with a confirm step and one-click unsubscribe that never asks you to log in. The blog also speaks webmention now, so when I link to someone's site their server hears about it, and when someone links here I see it in a moderation queue before anything shows on a post. And the big one: the blog is on the fediverse. You can follow it from Mastodon or anything compatible, and published posts land in your feed as a note. Everything coming back in, replies, likes, boosts, is held privately for me to read and never auto-published. The federation piece runs as its own small service, so if I ever want it gone I stop one container and the rest of the site never notices.

The site becomes a place. There is a hikes section now, turer, where each hike is a GPX track drawn on a real map, with distance and ascent computed from the file when I upload it. The map tiles come from OpenStreetMap and only load on those pages, which the privacy page now spells out. There is a training log, plain structured entries with a link to a post when a race deserves words, and the post gets a small stat box in return. And the drawings finally got their own section instead of hiding inside photo albums.

the admin dashboards page with error and traffic charts

The new dashboards page: errors, traffic, top posts, and when each service last shipped a log line.

The system watches itself. The admin panel got dashboards drawn from the analytics and the central log store, hand-rolled SVG charts, no chart library. Next to it sits alerting: every service now sends a heartbeat, and if one goes quiet, or errors start bursting, I get an email. Configured from the settings panel, off by default, like everything else here.

The publish button is where the whole wave meets. Publishing a post now queues newsletter emails, queues webmentions for every external link in it, and notifies followers on the fediverse, all on the same status transition:

if status == "published" && previousStatus != "published" {
	if err := s.Queries.EnqueueNewsletterPost(ctx, updated.ID); err != nil {
		recordErrorLog(r, http.StatusInternalServerError, "internal_error", ...)
	}
	if canonicalURL, err := s.Settings.GetString(ctx, "site.canonical_url"); err == nil {
		webmention.EnqueueOutbound(ctx, s.Queries, updated.ID, canonicalURL, updated.Content)
	}
	go s.notifyFederationPublish(updated)
} else if previousStatus == "published" && status != "published" {
	go s.notifyFederationUnpublish(updated)
}

Eight branches merging into one is where the mistakes live, and I collected a few. Two features had claimed the same database migration number, which the migration tool treats as two files both insisting they are step 21; one of them got renumbered before anything ran. The new federation service almost repeated an old outage: months ago the mail service sat silently disabled in production because one environment variable was empty, and the federation wiring had exactly the same empty-by-default variable waiting to do exactly the same thing. Caught it before deploy this time. And the deploy config itself forgot the new service existed, which would have had the server trying to build source code it does not have. The lesson version 2 taught still holds: the code being right is half the ship, the wiring around it is the other half.

That is version 3. The blog can be followed, subscribed to, and linked at. The site has places to walk, run, and draw. And when something breaks at three in the morning, it emails me instead of waiting to be noticed.

Follow this blog on the fediverse: @blog@blog.bjornmagne.com

0 comments

Log in to comment.

Log in

Forgot password?

No account?