How it fits together
The five services that make up the Rust Pulse platform, and how they talk to each other.
Rust Pulse is five separate services wired together. Knowing the boundaries helps when something looks broken — it's almost always one specific piece, not the whole thing.
┌────────────────────────┐
│ rustpulse.app (web) │ React dashboard
└───────────┬────────────┘
│ HTTPS + WSS
▼
┌────────────┐ ┌──────────────────┐ ┌──────────────┐
│ Overlay │──▶│ rustplus-api │──▶│ Postgres │
│ (Tauri) │ │ (Fastify, ESM) │ │ + Prisma │
└────────────┘ └────────┬─────────┘ └──────────────┘
│
┌──────────────┼─────────────────────────┐
▼ ▼ ▼
┌────────────┐ ┌──────────────┐ ┌───────────────┐
│ FCM worker │ │ Relay worker │ │ LibreTranslate│
└─────┬──────┘ └──────┬───────┘ └───────┬───────┘
│ │ │
│ FCM push │ Rust+ WebSocket │ /translate
▼ ▼ ▼
┌────────────────────────────────────────────────────┐
│ Facepunch + Rust+ (your server) │
└────────────────────────────────────────────────────┘
▲
│ FCM credentials
│ (encrypted at rest)
│
┌──────────┴───────────┐
│ Credentials Helper │ (your computer)
│ (Electron app) │
└──────────────────────┘
The pieces
rustplus-api
Node 20+, TypeScript ESM, Fastify, Prisma over Postgres. Routes live in src/routes/*:
- auth — Steam OpenID 2.0 login, session cookies.
- billing — Stripe Checkout + Portal + signed webhooks.
- credentials / pairing — encrypted FCM blob upload, device bearer-token issuance.
- paired-servers / intel — the dashboard's bread-and-butter reads.
- relay — short-lived JWT minting for the relay WebSocket.
- admin — everything the local admin portal hits.
- tools — FAQ, crafting, raid calculator, conveyor map.
FCM listener worker
A separate Node process (src/workers/fcm-listener.ts). One client per active user. Listens for the "you paired a server" push notifications from Rust+ and turns them into rows in PairedServer. Communicates back to the API via signed internal HTTP.
Relay worker
The hot path. src/workers/relay.ts plus src/services/rustplus-pool.ts. Keeps a live Rust+ WebSocket open per paired server, mirrors team chat, smart-device state, map markers, and writes events into Postgres. Dashboard and overlay clients subscribe over wss://.../v1?token=<jwt>.
Discord support bot
Separate process. Runs /faq, /ticket, /help, /post, the verify-button gate, and the live status board. Talks to the API over plain HTTPS for FAQ content. See Discord integration.
LibreTranslate
Self-hosted translation backend. Powers the in-game !translate command. Stateless — the API forwards requests, adds a Rust-slang dictionary, returns the result. See LibreTranslate.
Outside the platform
- Credentials Helper — Electron app that runs on the user's computer, captures FCM creds from Facepunch's site, uploads them encrypted to
rustplus-api. See Credentials Helper. - Overlay — Tauri app, also on the user's computer. Pairs once via Steam OpenID, then connects to the relay and paints a minimap on top of Rust. See Overlay.
Deploy targets
| Service | Where | Why |
|---|---|---|
| rustplus-api | Fly.io (fly.toml) | Long-running Fastify + Postgres |
| FCM listener | Fly.io (fly-fcm/) | Persistent FCM connections per user |
| Relay | Fly.io (fly-relay/) | Long-lived Rust+ sockets |
| Discord bot | Fly.io | Persistent gateway connection |
| LibreTranslate | Fly.io (private flycast) | CPU-bound translation models |
| Frontend | Fly.io / Vercel | Static dashboard SPA |
| Wiki | Fly.io / Vercel | This site |
| Credentials Helper | Electron installer | Runs on user's computer |
| Overlay | Tauri installer | Runs on user's computer |