SolaceCore is a Paper/Bukkit moderation plugin (kick, ban, tempban, mute, tempmute, unban, unmute) with a simple Vite + React web UI. The plugin stores players and punishments in MySQL/MariaDB, keeps basic stats, and exposes a REST API for the web.
– Plugin: Plugin/SolaceCore (Java 21, Maven, Paper 1.21.x)
– Web: WEB/SolaceCore (Node 20, Vite + React, Express API)
Language: English | Čeština (see README.cs.md)
- Moderation commands: /kick, /ban, /tempban, /unban, /mute, /tempmute, /unmute, and /menu
- MySQL/MariaDB persistence for players and punishments with automatic schema initialization
- Localization:
enandcs(choose inconfig.yml) - REST API (Express) to read players, punishments, stats, and cached skin “bust” images
- Web UI (React) with a dev proxy to the API; production build via Vite or Docker (Nginx)
Plugin/SolaceCore– Java plugin (Maven, Paper API)src/main/resources/config.yml– plugin config (language, DB)src/main/resources/plugin.yml– plugin metadata, commands, permissionsstart_server.bat– simple launcher for the Paper server (expectsserver/paper.jar)
WEB/SolaceCore– web + API (Node, Vite, React)server/index.js– Express API (+ skin cache)Dockerfile– production image for the web (Nginx)
- Plugin
- Java 21
- Maven 3.9+
- PaperMC 1.21.x (
paper.jarinPlugin/SolaceCore/server/) - MySQL/MariaDB instance
- Web
- Node.js 20+
- npm 10+
- Configure your database in
Plugin/SolaceCore/src/main/resources/config.yml:
language: en
database:
ip_address: "127.0.0.1"
port: "3306"
database_name: "solacecore"
user: "root"
password: ""- Prepare the Paper server:
- Create
Plugin/SolaceCore/server/ - Put
paper.jar(1.21.x) intoPlugin/SolaceCore/server/
- Build the plugin (Windows PowerShell):
cd Plugin/SolaceCore
mvn clean packageAfter the build, the resulting JAR is copied to server/plugins/SolaceCore-1.0.0.jar via the Maven antrun step.
- Optional: start the server through the Maven verify hook (uses
start_server.bat):
mvn verifyor manually:
cd server
./start_server.batOn first launch, the plugin automatically creates tables players, punishments, moderators, and roles.
Commands (per plugin.yml):
/kick <player> [reason]– permission:solacecore.kick/ban <player> [reason]– permission:solacecore.ban/unban <player>– permission:solacecore.unban/tempban <player> <time> [reason]– permission:solacecore.tempban/mute <player> [reason]– permission:solacecore.mute/tempmute <player> <time> [reason]– permission:solacecore.tempmute/unmute <player>– permission:solacecore.unmute/menu <player>– permission:solacecore.menu
Additional permissions (protections): solacecore.banprotection, solacecore.kickprotection, solacecore.muteprotection. By default, all permissions are default: op.
Time arguments support suffixes s, m, h, d (e.g., 10m, 2h, 1d).
- Language files:
Plugin/SolaceCore/src/main/resources/lang/en.ymlandcs.yml - Choose language:
language: enorlanguage: csinconfig.yml
Dev mode (Vite + Express run concurrently; /api is proxied to the backend):
cd WEB/SolaceCore
npm ci
npm run devWhat starts:
- Vite dev server at http://localhost:5173
- Express API at http://localhost:3001 (
server/index.js) - Proxy
/api->http://localhost:3001configured invite.config.ts
Production build (static web):
npm run build
npm run previewDocker for the web (Nginx):
cd WEB/SolaceCore
docker build -t solacecore-web .
docker run -p 8080:80 solacecore-webAPI reads environment variables (defaults in parentheses):
PORT (3001)
DB_HOST (127.0.0.1)
DB_PORT (3306)
DB_USER (root)
DB_PASSWORD ("")
DB_NAME (solacecore)
SKIN_TTL_DAYS (30)
ENABLE_CORS (0/1) – enable CORS if you are not using the Vite proxy
Example .env in WEB/SolaceCore:
PORT=3001
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_NAME=solacecore
ENABLE_CORS=0GET /api/health– DB healthcheckGET /api/players– list of players{ uuid, name }GET /api/players/:uuid/punishments– player punishments by UUID (used by the web modal)GET /api/stats– aggregates:bansToday,totalBans,totalPunishmentsGET /api/skins/:id/bust– PNG skin “bust” with on-disk cache (30 days),?force=1to force refresh
Note: The API expects the plugin to maintain the DB schema and data. The schema is created by the plugin at startup.
The current data model uses 4 main tables: players, punishments, moderators, roles.
nameVARCHAR(16)NOT NULLPRIMARY KEYuuidVARCHAR(36)UNIQUENULLipAddressVARCHAR(45)NULLlastLoginDATETIMENULL
Indexes:
INDEX (uuid)INDEX (ipAddress)
idINTNOT NULLAUTO_INCREMENTPRIMARY KEYplayer_nameVARCHAR(16)NOT NULLreasonVARCHAR(255)NULLoperatorVARCHAR(16)NULLpunishmentTypeVARCHAR(16)NULLstartDATETIMENULLendDATETIMENULLdurationBIGINTNULL(in seconds)isActiveBOOLEANNULL
Indexes:
INDEX (player_name)
FK:
fk_punishments_player_name:punishments.player_name->players.nameON DELETE CASCADEON UPDATE CASCADE
idINTAUTO_INCREMENTPRIMARY KEYusernameVARCHAR(50)UNIQUENOT NULLpassword_hashVARCHAR(255)NOT NULLrolesJSONNULL(array of role IDs, e.g.[1,2])is_activeBOOLEANDEFAULT TRUE
Indexes:
INDEX idx_username (username)
idINTAUTO_INCREMENTPRIMARY KEYnameVARCHAR(50)UNIQUENOT NULLpermissionsJSONNOT NULL(e.g.{"ban": true, "kick": true})
Indexes:
INDEX idx_name (name)
- Physical FK relationship in DB:
players (1)->punishments (N)viapunishments.player_name
- Logical relationship (without FK constraint):
moderators.roles(JSON array) contains IDs fromroles.id
- Recommended server: Paper 1.21.x
- Compiled for Java 21 (use Java 21 for the server)
- For production, run the API server (Express) separately; the provided Dockerfile packages only the static web (Nginx)
Issues and PRs are welcome. Please follow the existing code style and include a short description of your changes.
TBD. Please add a LICENSE file once a license is chosen.