Files

Group Ironmen Backend - Java/Spring Boot

A complete rewrite of the Group Ironmen tracker backend from Rust to Java/Spring Boot, maintaining 100% API compatibility with the existing RuneLite plugin.


🎯 Project Status

COMPLETE - Ready for Deployment

All core functionality implemented and tested:

  • Database layer (JPA entities, repositories)
  • Security layer (Blake2 token authentication, CORS)
  • Business logic (services for groups, members, GE prices)
  • REST API (all endpoints matching Rust implementation)
  • Exception handling
  • Build successful

📋 Table of Contents


Features

Core Features

  • Group Management: Create groups with up to 5 members
  • Member Tracking: Track player stats, skills, inventory, equipment, bank, etc.
  • Delta Updates: Efficient updates - only changed data is sent
  • GE Prices: Cached Grand Exchange prices updated every 4 hours
  • Token Authentication: Blake2-hashed tokens for secure access
  • Per-Field Timestamps: Track last update time for each member field

API Compatibility

  • 100% compatible with existing RuneLite plugin
  • Identical JSON structure to Rust backend
  • Same authentication flow
  • Same endpoint paths and parameters

🛠️ Technology Stack

  • Java 17 - LTS version
  • Spring Boot 3.2.0 - Application framework
  • Spring Security - Authentication & authorization
  • Spring Data JPA - Database access
  • MariaDB - Database (MySQL-compatible)
  • Flyway - Database migrations
  • Lombok - Reduce boilerplate code
  • Gradle 8.5 - Build tool
  • Bouncy Castle - Blake2 cryptography

🚀 Quick Start

Prerequisites

  • Java 17 or higher
  • MariaDB 10.6+ (or MySQL 8.0+)
  • Gradle 8.5+ (wrapper included)

1. Clone Repository

cd leagues-tools/spring-backend

2. Setup Database

CREATE DATABASE groupironman CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'groupironmen'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON groupironman.* TO 'groupironmen'@'localhost';
FLUSH PRIVILEGES;

3. Configure Application

Edit src/main/resources/application.yml or set environment variables:

export DB_HOST=localhost
export DB_PORT=3306
export DB_NAME=groupironman
export DB_USER=groupironmen
export DB_PASSWORD=your_password
export BACKEND_SECRET=your_64_char_random_secret
export CORS_ORIGINS=http://localhost:3000,http://localhost:4000

4. Build and Run

# Build
./gradlew clean build

# Run
./gradlew bootRun

# Or run JAR directly
java -jar build/libs/group-ironmen-backend-1.0.0.jar

5. Test

# Health check
curl http://localhost:8080/api/ge-prices

# Create group
curl -X POST http://localhost:8080/api/create-group \
  -H "Content-Type: application/json" \
  -d '{"name": "Test Group", "member_names": ["Player1", "Player2"]}'

📡 API Endpoints

Public Endpoints (No Authentication)

Method Endpoint Description
POST /api/create-group Create a new group
GET /api/ge-prices Get cached GE prices
GET /api/captcha-enabled Get captcha configuration
GET /api/collection-log-info Get collection log metadata

Group Endpoints (Token Authentication Required)

Method Endpoint Description
GET /api/group/{name}/get-group-data Get member data (supports delta updates)
GET /api/group/{name}/am-i-logged-in Check authentication
GET /api/group/{name}/am-i-in-group Check member membership
GET /api/group/{name}/get-skill-data Get skill progression data
GET /api/group/{name}/collection-log Get collection log data

Member Endpoints (Token Authentication Required)

Method Endpoint Description
POST /api/group/{name}/update-group-member Update member data (from plugin)
POST /api/group/{name}/add-group-member Add new member to group
DELETE /api/group/{name}/delete-group-member Remove member from group
PUT /api/group/{name}/rename-group-member Rename a member

⚙️ Configuration

Environment Variables

Variable Default Description
DB_HOST localhost MariaDB host
DB_PORT 3306 MariaDB port
DB_NAME groupironman Database name
DB_USER root Database username
DB_PASSWORD password Database password
SERVER_PORT 8080 Application HTTP port
BACKEND_SECRET changeme Token hashing secret (CHANGE IN PRODUCTION!)
CORS_ORIGINS * Allowed CORS origins (comma-separated)
CAPTCHA_ENABLED false Enable hCaptcha validation
CAPTCHA_SITEKEY hCaptcha site key
CAPTCHA_SECRET hCaptcha secret key

Application Properties

See src/main/resources/application.yml for all configuration options.


🚢 Deployment

For Debian/Proxmox VE

See DEPLOYMENT.md for complete guide including:

  • LXC container setup
  • MariaDB installation & configuration
  • systemd service creation
  • Nginx reverse proxy setup
  • SSL certificate installation
  • Monitoring and maintenance

Quick Deploy Script

# Build JAR
./gradlew clean build -x test

# Copy to server
scp build/libs/group-ironmen-backend-1.0.0.jar user@server:/opt/group-ironmen-backend/

# Restart service (on server)
ssh user@server "systemctl restart group-ironmen-backend"

💻 Development

Project Structure

spring-backend/
├── src/main/java/com/osleague/groupironmen/
│   ├── GroupIronmenApplication.java    # Main application
│   ├── config/                         # Configuration classes
│   ├── controller/                     # REST controllers
│   ├── dto/                            # Data Transfer Objects
│   ├── exception/                      # Custom exceptions
│   ├── model/                          # JPA entities
│   ├── repository/                     # Spring Data repositories
│   ├── security/                       # Security components
│   ├── service/                        # Business logic
│   └── util/                           # Utilities
├── src/main/resources/
│   ├── application.yml                 # Main configuration
│   └── db/migration/                   # Flyway migrations
├── build.gradle                        # Build configuration
└── README.md                           # This file

Building

# Clean build
./gradlew clean build

# Skip tests
./gradlew build -x test

# Run tests only
./gradlew test

# Generate JAR
./gradlew bootJar

Code Style

  • Java code formatted with standard conventions
  • Lombok used to reduce boilerplate
  • Comprehensive Javadoc comments
  • Follows Spring Boot best practices

🧪 Testing

Unit Tests

./gradlew test

Integration Tests (Requires MariaDB)

./gradlew integrationTest

Manual Testing with curl

Create Group:

curl -X POST http://localhost:8080/api/create-group \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Test Group",
    "member_names": ["Player1", "Player2", "Player3"]
  }'

# Save the returned token!

Update Member (as Plugin would):

curl -X POST http://localhost:8080/api/group/My%20Test%20Group/update-group-member \
  -H "Content-Type: application/json" \
  -H "Authorization: YOUR_TOKEN_HERE" \
  -d '{
    "name": "Player1",
    "stats": [99, 99, 100, 301],
    "skills": [13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431, 13034431]
  }'

Get Group Data:

curl http://localhost:8080/api/group/My%20Test%20Group/get-group-data \
  -H "Authorization: YOUR_TOKEN_HERE"

📚 Documentation

Available Documentation

Key Design Decisions

1. MariaDB JSON Columns

  • PostgreSQL arrays → MariaDB JSON columns
  • Uses @JdbcTypeCode(SqlTypes.JSON) annotation
  • Maintains compatibility with Rust schema

2. Blake2 Token Hashing

  • 100% compatible with Rust implementation
  • 2 iterations of Blake2b-256
  • Token + secret + group_name as salt

3. Delta Updates

  • Per-field last_update timestamps
  • Only changed fields returned in responses
  • Reduces bandwidth for plugin updates

4. Stateless Authentication

  • Token in Authorization header
  • No session storage
  • Group ID extracted from token validation

🔐 Security

Authentication Flow

  1. Client sends Authorization: {token} header
  2. TokenAuthenticationFilter intercepts request
  3. Token is hashed with Blake2
  4. Database lookup: SELECT group_id WHERE token_hash = ? AND group_name = ?
  5. If valid, group_id set in Spring Security context
  6. Controller accesses group_id from Authentication principal

Security Best Practices

  • Tokens are hashed (never stored in plain text)
  • CORS properly configured
  • SQL injection prevented (JPA parameterized queries)
  • Input validation on all endpoints
  • HTTPS recommended for production
  • Secrets via environment variables (not in code)

🐛 Troubleshooting

Build Failures

# Clean and rebuild
./gradlew clean build --refresh-dependencies

# Check Java version
java -version  # Should be 17+

Database Connection Issues

# Test connection
mysql -h localhost -u groupironmen -p groupironman

# Check Flyway migrations
./gradlew flywayInfo
./gradlew flywayMigrate

Application Won't Start

# Check logs
./gradlew bootRun --debug

# Verify port 8080 is available
netstat -an | grep 8080

🤝 Contributing

This is a migration project. Key compatibility requirements:

  • Maintain exact API compatibility with RuneLite plugin
  • Keep JSON structure identical to Rust implementation
  • Preserve authentication mechanism (Blake2 hashing)
  • Match database schema (via Flyway migrations)

📄 License

Same license as the original Rust project.


  • Rust Backend (original): group-ironmen-master/server/
  • Frontend (Web Components): group-ironmen-master/site/
  • RuneLite Plugin: group-ironmen-tracker-master/
  • League Tools Frontend: os-league-tools-master/

📞 Support

For issues or questions:

  1. Check existing documentation in this repository
  2. Review Rust implementation for reference
  3. Test with RuneLite plugin to verify compatibility

Status: Complete and ready for deployment Version: 1.0.0 Last Updated: 2025-10-27