Files
minecraft-account-manager/docs/architecture.md
T
dmg 24808b0f8c
CI / validate (push) Successful in 5m39s
Release / release (push) Successful in 7m15s
fix(dashboard): show enriched network details
2026-08-02 08:05:57 -04:00

4.1 KiB

Architecture

Services

Web application

The Next.js application owns user onboarding, account management, admin configuration and metrics, server-side Minecraft profile validation, sessions, and the HTTP API used by Discord and Velocity integrations. Database-backed portal and console pages are dynamic React Server Components: authentication, queries, filtering, dashboard aggregation, and the initial Natural Earth user-location map execute on the server and return rendered HTML. Administrators can opt into a hydrated Leaflet/OpenStreetMap view; OSM receives requests only for viewed map tiles, while user marker coordinates remain local to the browser.

User authentication begins with an opaque, short-lived, single-use token created for a Discord user. Only a cryptographic hash of the token is persisted. Admin authentication is a separate Keycloak OIDC flow and requires the minecraft-account-manager-admin role.

Discord bot

The bot creates private login links in response to /register and /account. Discord user IDs are the canonical Discord identity; mutable usernames are snapshots only. Nickname updates target the deployment guild configured by DISCORD_GUILD_ID; the public join button uses DISCORD_INVITE_URL.

Velocity plugin

Velocity sends the authenticated Java UUID, current username, source IP, server ID, request ID, and occurrence time. The API matches UUID first. Username fallback is allowed only when the stored account has no UUID, after which UUID and canonical username are updated.

The admission decision is fail closed. Unknown players, invalid responses, expired requests, authentication failures, and unavailable API responses are denied with the configured registration message. After admission succeeds, PostLoginEvent reports a confirmed proxy connection through a fresh, authenticated, replay-protected request. Connection telemetry is best effort and never disconnects an already admitted player.

Trust boundaries

  • Browser input is untrusted. Minecraft profile resolution occurs on the server.
  • Forwarded IP headers are accepted only from configured reverse proxies.
  • Discord IDs come from bot-authenticated requests or one-time-code records, not browser fields.
  • Velocity requests use hashed per-server bearer credentials, timestamps, and database-unique request IDs for authentication and replay prevention.
  • Session and one-time-code values are random and stored only as hashes.
  • Exact IP addresses are sensitive data and require an explicit retention policy before production deployment.

Database invariants

  • A Discord user ID maps to one user.
  • An active Minecraft UUID or case-insensitive username maps to one account.
  • A user has at most one active primary Minecraft account.
  • Removed accounts are soft deleted to retain audit history.
  • Audit events are CloudEvents-shaped, append-only application records.
  • published_at reserves an outbox-style path for later Kafka publishing.

IP intelligence

ProxyCheck.io supplies approximate city/region/country, coordinates, timezone, ASN, network company, connection type, proxy signal, risk, and VPN/proxy/Tor classification. Results are cached in PostgreSQL for 48 hours by default. Portal and game login events are enriched when data is available; lookup failures do not deny login. User Minecraft-account additions fail closed for unknown, VPN, proxy, or Tor classifications and record denied attempts. Hosting-provider blocking is optional through BLOCK_HOSTING_IPS=true. Private and reserved addresses are never sent to ProxyCheck.

Event naming

Events use reverse-DNS names beneath games.minecraft.account-manager, including:

  • games.minecraft.account-manager.ui.accessed
  • games.minecraft.account-manager.auth.magic-link.consumed
  • games.minecraft.account-manager.minecraft-account.added
  • games.minecraft.account-manager.minecraft-account.removed
  • games.minecraft.account-manager.discord.nickname.updated
  • games.minecraft.account-manager.network.vpn-blocked
  • games.minecraft.account-manager.game.login.allowed
  • games.minecraft.account-manager.game.login.denied
  • games.minecraft.account-manager.game.player.connected