id: c0cf480db3ee4daea7cebc04dc635003
parent_id: 4a7fcbf3efca4cd7a12aabd5d10a2c45
item_type: 1
item_id: 980c3eb587294e4383474b94988f2f88
item_updated_time: 1785658160794
title_diff: "[]"
body_diff: "[{\"diffs\":[[0,\")\\\n\\\n---\\\n\\\n\"],[1,\"## Deployment Topology (self-hosted)\\\n\\\n> Resolved 2026-08-02. Canonical reference: [Development Environment & Server Topology](joplin://bbc49a3bbada4fcdb8fedc66abf5014e). Git source of truth: Forgejo on the Hetzner box ([migration note](joplin://91ddc5785c174087b03fa6ae216a8611)).\\\n\\\n| Tier | Machine (OS) | Runtime |\\\n|---|---|---|\\\n| **Develop** | workhorse (Ubuntu 26.04, Ryzen 9 5950X 16C/32T, 128 GiB, RTX 5060 Ti) | Kilo + RustRover/WebStorm; full stack locally via `docker-compose.yml` (PostgreSQL 16 + Redis 7); backend `cargo run`, frontend Vite. 32 threads → fast incremental builds. |\\\n| **Test / Stage** | basement server (FreeBSD) | **Jenkins** CI (lint → test → build → Docker image, tagged by git SHA). A **bhyve Debian VM** runs the *same* Docker Compose as prod (separate DB, `staging.<domain>`), mirroring the prod OS. Also the artifact + backup store. |\\\n| **Produce** | Hetzner box (Debian) | Public entry point. One **Caddy** (TLS) already fronts **Forgejo**; add `api.<domain>` → game API (Docker) and `play.<domain>` → built static frontend. Prod Docker Compose = PostgreSQL + Redis + app image (tagged). Jenkins deploys by SSH + `docker compose up -d`. |\\\n\\\n**Flow:** commit on workhorse → push Forgejo (Hetzner) → Jenkins (basement) builds & images → deploys to bhyve Debian staging → on green, Jenkins deploys the same image tag to Hetzner prod.\\\n\\\n**Sizing caveat:** the Hetzner box is \\\"decent, not a powerhouse\\\" and already runs Forgejo. A Rust text MMORPG is light, but watch combined RAM (Forgejo + PG + Redis + app). Set a threshold for upsizing the box or splitting DB/app onto a second VPS. bhyve on the basement box can also host a hot-spare/standby if needed.\\\n\\\n**Why a Debian bhyve guest for staging (not a FreeBSD jail):** production is Debian + Docker. Running staging in a matching Debian VM catches kernel/glibc/runtime surprises the Docker layer doesn't fully hide. Use FreeBSD jails only for FreeBSD-native services (file server, Jenkins, backups), not for the Docker-based game.\\\n\\\n---\\\n\\\n\"],[0,\"## Multi\"]],\"start1\":531,\"start2\":531,\"length1\":16,\"length2\":2033},{\"diffs\":[[0,\"ructure\\\n\"],[-1,\"\"],[0,\"\\\nThe pro\"]],\"start1\":2572,\"start2\":2572,\"length1\":16,\"length2\":16},{\"diffs\":[[0,\"stants\\\n```\\\n\\\n\"],[1,\"> Source of truth is **Forgejo** on Hetzner, not GitHub — the `github.com/{org}/` path above is conceptual only. See [Deployment Topology](#deployment-topology-self-hosted).\\\n\\\n\"],[0,\"### Local Ch\"]],\"start1\":2940,\"start2\":2940,\"length1\":24,\"length2\":199},{\"diffs\":[[0,\"her IDE\\\n\"],[-1,\"\"],[0,\"```\\\n\\\n\"],[1,\"> This follows the cross-project workspace convention `~/dev/<project>/`. On workhorse, legacy repos still live in per-IDE default folders (`~/RustroverProjects`, `~/WebstormProjects`, `~/IdeaProjects`); relocate on first touch, or clone into `~/dev/skara-brae/` and symlink the repo back into the IDE folder for discoverability — but always open the **real path** in the IDE so path/file deps resolve. Full convention in [Development Environment & Server Topology § Workspace & Repository Layout](joplin://bbc49a3bbada4fcdb8fedc66abf5014e).\\\n\\\n\"],[0,\"- **Rust\"]],\"start1\":3632,\"start2\":3632,\"length1\":21,\"length2\":564},{\"diffs\":[[0,\" Notes\\\n\\\n\"],[1,\"- [Development Environment & Server Topology](joplin://bbc49a3bbada4fcdb8fedc66abf5014e) — Canonical dev/test/prod machine roles, toolchain, workspace layout\\\n\"],[0,\"- [Game \"]],\"start1\":22351,\"start2\":22351,\"length1\":16,\"length2\":174}]"
metadata_diff: {"new":{},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-08-02T08:09:54.733Z
created_time: 2026-08-02T08:09:54.733Z
is_locked: 0
type_: 13