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
- Technology Stack
- Quick Start
- API Endpoints
- Configuration
- Deployment
- Development
- Testing
- Documentation
✨ 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
- IMPLEMENTATION_STATUS.md - Detailed implementation guide
- BUILD_STATUS.md - Build instructions and status
- STATUS_UPDATE.md - Latest development progress
- DEPLOYMENT.md - Production deployment guide (Debian/Proxmox)
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_updatetimestamps - 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
- Client sends
Authorization: {token}header TokenAuthenticationFilterintercepts request- Token is hashed with Blake2
- Database lookup:
SELECT group_id WHERE token_hash = ? AND group_name = ? - If valid,
group_idset in Spring Security context - Controller accesses
group_idfromAuthenticationprincipal
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.
🔗 Related Projects
- 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:
- Check existing documentation in this repository
- Review Rust implementation for reference
- Test with RuneLite plugin to verify compatibility
Status: ✅ Complete and ready for deployment Version: 1.0.0 Last Updated: 2025-10-27