Transporter Room: giving a backup tool a bridge console

A command-line backup engine deserves a control panel with some personality. Transporter Room is an Avalonia desktop app with an amber-and-cyan status deck, and it has a web sibling for the server closet.

2 min read

Painted illustration of a retro sci-fi transporter console with amber lights and a shimmering column of light on a pad.

In my last post I wrote about PatternBuffer.NET, my Borg-inspired backup engine and its beam command. The CLI is how I build backups. But the backups I actually run are the ones that are pleasant to start, and a terminal full of flags isn't that. Backups need a big friendly button.

So beam got a control room.

A console, not a form

Transporter Room is an Avalonia desktop app, and I leaned into the theme on purpose. Instead of a gray dialog with a progress bar, you get a layered hull, illuminated “archive chambers,” console lights, and an amber-and-cyan status deck. All of it is drawn with Avalonia vector composition, with no bitmap assets, so it scales cleanly with the window.

The centerpiece is the status beam: a custom-drawn transporter effect with a rising particle shimmer and a vertical “materialization field” that gets brighter as beam reports progress. It's silly, and it's also genuinely useful. You can read the state of a backup from across the room.

A few practical decisions under the theming:

  • The BACKUP NOW command deck is fixed directly above the status area. The repository, archive, and source panels scroll on their own, so the button never scrolls away.
  • The archive name is optional. Leave it blank and beam generates a stardate name like stardate-2026.68.
  • A FILTERS library has exclusion presets for .NET and Visual Studio output, Node, Python, JVM, Rust, Go, logs, and OS clutter, plus a box for hand-written globs. Each selection becomes an --exclude argument.
  • A circular ? button opens an operator's manual, because the stardate format and filters deserve an explanation somewhere.

Keeping the engine separate

The most important design decision isn't visible at all. Transporter Room doesn't contain a backup engine. It launches beam and talks to it over a versioned JSON protocol: capabilities, progress, and results all come back as structured messages instead of scraped console text.

That boundary means the CLI stays the single source of truth. Anything the GUI can do, I can script, and a GUI bug can't corrupt a repository. It also made the second front end easy.

The web sibling

Transporter Room .NET is an ASP.NET Core 10 Blazor Server dashboard for the machine that holds the repositories. It has a first-run setup flow, administrator and user accounts, host telemetry (CPU, memory, storage), deduplication and compression stats, and archive history per repository. It builds a client inventory from the host and OS metadata stored in each archive, and it generates copyable beam up, beam list, and beam down commands for any client.

It has one rule I'm strict about: the dashboard observes; it never starts a backup. It runs beam info and beam list for telemetry, and beam init only when an authenticated user creates a repository. Scheduling stays on the clients where it belongs. A web page that can quietly kick off backups on every machine in the house is a web page that will eventually do it at the worst possible moment.

Passphrases for encrypted repositories are passed to beam once during initialization and never stored. The dashboard simply reports those repositories as locked. I'm fine with that trade.

Make it useful, then make it fun to use. The fun part is why I actually press the button.