Files
SCOPENET-MC/docs/architecture.md
T
Claude 5dc8a4f2f1 Add Docker image, Compose, CI/CD workflows and docs
- Multi-arch (amd64/arm64) panel image: static musl binary on scratch,
  cross-compiled with cargo-zigbuild (no QEMU), non-root, healthcheck
- docker-compose.yml + .env.example for one-command deployment
- CI: fmt, clippy, tests, web type-checks, Windows launcher build,
  real-network installs of vanilla/Fabric/Quilt/Forge/NeoForge,
  Docker build
- Release: Windows NSIS installer with baked-in panel URL, GHCR image
  push and GitHub release (tag push or manual dispatch)
- README, admin guide, Microsoft auth setup, architecture, development
- rustfmt config and formatting pass

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ARcGWxLx21FwXJ3yfGriS
2026-09-28 05:19:36 +00:00

3.7 KiB

Architecture

┌──────────────────────────┐        HTTPS (JSON)        ┌──────────────────────────┐
│  Launcher (Tauri)        │ ─────────────────────────▶ │  Panel (Axum + SQLite)   │
│  Svelte UI ⇄ Rust shell  │   manifest, instances,     │  Svelte admin UI         │
│        │                 │   auth, stats              │  /files, /uploads        │
│  scopenet-core engine    │                            └──────────────────────────┘
│   ├─ Mojang / Java       │ ──▶ piston-meta, libraries.minecraft.net, resources
│   ├─ Fabric/Quilt/Forge  │ ──▶ meta.fabricmc.net, maven.minecraftforge.net, …
│   └─ modpack files       │ ──▶ Modrinth/CurseForge CDNs, panel /files
└──────────────────────────┘
  • crates/shared defines every JSON type exchanged, so the panel and launcher can't drift apart.
  • crates/core has no UI dependencies. It's unit-tested, and CI runs real installs of vanilla, legacy, Fabric, Quilt, Forge and NeoForge against the live servers.
  • The panel also uses core for version and loader lookups.

Launch pipeline

  1. Resolve the account (refreshing Microsoft tokens if needed).
  2. Fetch the instance from the panel (cached for offline play).
  3. install: vanilla version JSON → Java runtime (Mojang's own builds) → client jar, libraries, assets → loader profile (Fabric/Quilt), or replay the Forge/NeoForge installer's processors → merge → natives.
  4. sync: download the admin's files; remove files the admin removed; never touch the player's own files. With an unchanged revision, only existence is checked.
  5. Write servers.dat and keybinds, build the Java command (quick play / --server, memory, GC presets, @argfile for long classpaths), and start the game.
  6. Stream logs to the console; on a crash, show the tail of the log with hints.

Disk layout (launcher)

%APPDATA%\net.scopenet.launcher\
  settings.json, accounts.json, secrets.bin (encrypted), manifest.json (cache)
  minecraft\
    versions\  libraries\  assets\  runtimes\  natives\  cache\
    instances\<id>\        ← game directory (saves, mods, options.txt, …)

HTTP API

Public (used by launchers). Send Authorization: Bearer <token> to see restricted instances:

Method Path
GET /api/v1/launcher/manifest Branding, auth options, visible instances
GET /api/v1/launcher/instances/{id} Instance + file list
POST /api/v1/launcher/events Launch stats
POST /api/v1/auth/login · /register Panel accounts
GET /api/v1/auth/me Current user
GET /files/{instance}/{path} Hosted instance files
GET /healthz Health check

Admin (role = admin): /api/admin/{stats,users,groups,branding,settings,instances,uploads} plus instances/{id}/{import/modrinth,import/curseforge,import/upload,files,reset} and meta/search proxies under /api/admin/{meta,modrinth,curseforge}.

Security notes

  • Passwords are hashed with Argon2id; tokens are HS256 JWTs (30 days); disabled accounts are rejected on every request.
  • Server-provided paths are sanitised (safe_join) on both sides — no .. or absolute paths.
  • The panel never returns the CurseForge key; SVG uploads are refused (script risk).
  • The launcher's CSP only allows scripts from the app itself; media may load from any HTTPS host (admin-chosen images).
  • Hosted /files are public URLs. Don't put secrets in instance files.