3.5 KiB
3.5 KiB
ShbDiscordBot contributor guide
Purpose and invariants
This repository builds one Paper plugin which embeds a JDA Discord bot. Discord is the entry point for issuing short-lived link codes, Minecraft is the only place where a code can be consumed, and ShbUtils Core API is the source of truth for persistent Discord-to-Minecraft links.
/authis a global Discord slash command intended for bot DMs./link <six-digit-code>is a player-only Paper command./sdb reloadis the operator-only full runtime/config reload command. Do not override Paper's built-in/reloadcommand.- Link codes are process-local, single-use, active for ten minutes by default, and must never be logged.
- Existing Discord or Minecraft links must not be overwritten.
- Discord roles only grant LuckPerms nodes. This project deliberately does not revoke them.
Build and verification
- Use Java 25 and the checked-in Gradle wrapper.
./gradlew testruns the automated test suite../gradlew shadowJarcreates the deployable plugin JAR; the plain JAR does not include JDA/Jackson../gradlew buildmust pass before handing work off.- LuckPerms and Paper are compile-only/server-provided dependencies. Do not shade either of them.
Architecture rules
- Keep configuration parsing, Discord/JDA integration, ShbUtils HTTP transport, link orchestration, Paper commands, and LuckPerms synchronization in separate classes.
- Do not perform network requests, JDA waits, or LuckPerms user loads on the Paper main thread.
- Only touch Bukkit player/server state on the Paper main thread. Capture UUIDs and immutable values before crossing thread boundaries.
- Make scheduled role scans non-overlapping and bound API concurrency.
- Treat API
401and validation/conflict responses as permanent failures; treat I/O, timeouts,429, and5xxas retryable. - On disable, cancel tasks and close JDA plus plugin-owned executors.
- A runtime reload must validate the new config before stopping the current runtime, invalidate pending codes, await JDA shutdown off the Paper thread, recreate all config-bound services, and immediately run role synchronization.
Security and configuration
- Never commit real Discord tokens or
X-Internal-Secretvalues. The resourceconfig.ymlcontains empty placeholders only. - Never include secrets, bearer tokens, full HTTP headers, or active link codes in logs or exceptions shown to players.
- Parse Discord snowflakes as strings/unsigned IDs and Minecraft identifiers as UUIDs.
- Generate codes with
SecureRandom; preserve leading zeroes and enforce rate limiting when consuming invalid codes.
API contract and documentation
- The local API reference is
docs/API.md, based onhttps://api.shlakoblock.com/api.json. - Runtime code uses only internal status and Discord-link endpoints. Do not use the API verification-code endpoints for the Discord-to-Minecraft flow: those endpoints implement the reverse direction.
- When the upstream OpenAPI version changes, compare every path/schema and update
docs/API.md, DTOs, tests, and the recorded snapshot date together.
Testing expectations
- Cover code uniqueness, expiry, replacement, rate limiting, reservation/release, and concurrent single-use behavior.
- Test HTTP paths, JSON fields, internal-secret headers, status handling, and timeout/error classification without contacting production.
- Test role-to-permission union, idempotent grants, unlinked users, and grant-only behavior.
- A feature is incomplete if it can block the Paper main thread or leak a secret/code to logs.