Skip to main content
Back to articles
2026 / 02
| 4 min read

Server-Backed Backends and Peripherals Go Physical

Migrating backends to server APIs with NATS pub/sub, adding microservices, and building the peripheral slot system alongside the Canada Goose game.

emulator microservices nats redis peripherals
On this page

The emulator has been a browser island: fast to ship, easy to iterate, allergic to persistence. That shape stops working the moment you need shared state, moderation, or anything that outlives a tab. Today I cut over to a real backend: three gRPC services, a WebSocket gateway, and NATS for real-time events.

Backends Become Services

Three gRPC services now own the heavy data paths:

  • users-service on port 50051 for profiles, presence, and account settings.
  • messaging-service on port 50052 for BBS, Usenet, and email.
  • market-service on port 50053 for quotes, portfolios, and trades.

Each service lives in its own Rust crate with its own tables, and each talks to a Redis-compatible cache (Dragonfly) for hot reads. The WebSocket gateway is the single entry point; it routes requests into the correct service and emits real-time events over NATS so other connected clients can react.

HTTP/WS

events

Frontend + Emulator

API Gateway

Users Service

Messaging Service

Market/Stocks Service

Cloud Storage

Redis/Dragonfly

NATS Pub/Sub

The gateway doesn’t implement business logic; it forwards and emits. That keeps failures local to whichever service caused them.

Quotes: Finnhub With A Fallback

The stock ticker backend now uses Finnhub instead of Yahoo. Yahoo’s cookie and crumb flow was brittle enough that I was spending my time on auth rather than market logic. Finnhub is predictable: one request per symbol, then a five‑minute sleep.

When the API fails or the key is missing, the ticker falls back to a random‑walk simulation, so the UI keeps moving even when the world goes quiet.

Flow Control Stops Dropping Bytes

The server move surfaced a serial problem I’d been living around: large payloads over slow links overrun the modem buffer if you don’t respect CTS. That’s a correctness issue, not a performance one. When CTS drops, output queues; when it rises, output drains. With that enforced, the “missing welcome screen” bug disappeared.

Peripherals Grow A Physical Layer

The other thread today is visual. A peripheral should feel like a piece of hardware rather than a menu entry, which means a fixed place, a consistent affordance, and a face you can zoom into.

I built a slot system and a modal viewer that scales from the slot’s position. The modal’s transform‑origin is computed from the source element’s bounding box, so it reads as pulling a device forward from the chassis instead of opening a new page. The peripheral manager owns the mapping from device IDs to Lit component tags and lazy‑creates the full view on first zoom.

Slot → device → view. Naming it that way made the rest of the work mechanical.

Canada Goose And DATAPAC

Two new backends:

  • Canada Goose Simulator: a text adventure with a day‑night loop, multiple victory conditions, and an audio generator that produces honks, flaps, and splashes. It’s also a good stress test for the serial UI stack, since it emits both dense text and short prompts.
  • DATAPAC X.25: a simulator for Canada’s packet network, which opened in 1977 and was finally shut down at the end of 2009, including PAD command mode and virtual host routing.

Both are weird by design. The project is more interesting when the platform can host sensible tools and niche history side by side.

OAuth Handle Selection

OAuth users now choose their own handle instead of inheriting an auto‑generated one. The rules: 3–16 characters, ASCII letters, numbers and underscores only, no GUEST_ prefix. The availability check runs before the account is created, so the pending OAuth token stays valid if the first choice is taken.

That ordering is the difference between a retryable form and a support ticket.

What Changed

  • Migrated multiple backends behind the gateway and split them into users-service, messaging-service, and market-service.
  • Added NATS for real‑time events and Redis/Dragonfly for shared caching.
  • Switched stock quotes to Finnhub with a random‑walk fallback.
  • Shipped the peripheral slot + modal system with scale‑from‑source animation.
  • Added Canada Goose Simulator and DATAPAC X.25 backends.
  • Implemented OAuth handle selection with strict validation rules.

What’s Next

Tomorrow: SignalBus subscriptions across the peripheral slots — floppy, cassette, hard drive, CD-ROM — so they can react to system state. The slot views exist; right now they’re inert.

Previous: 2026-01-31