9.5 KiB
Group Ironmen Backend - Implementation Status
Project Overview
Goal: Migrate group-ironmen-master Rust backend to Java/Spring Boot while maintaining 100% API compatibility with RuneLite plugins.
Technology Stack:
- Java 17
- Spring Boot 3.2.0
- MariaDB
- Gradle
- Flyway (database migrations)
- Bouncy Castle (Blake2 hashing)
✅ Completed Components
1. Project Setup
- Gradle build configuration (
build.gradle) - Application configuration (
application.yml) - Main application class (
GroupIronmenApplication.java) - Package structure created
2. Database Layer
- Flyway migration script (
V1__init_schema.sql)- MariaDB-compatible schema
- JSON columns for arrays (instead of PostgreSQL arrays)
- All tables: groups, members, skills_, collection_
- Indexes and foreign keys
3. Security & Authentication
-
Blake2TokenHasher (
Blake2TokenHasher.java)- 100% compatible with Rust implementation
- 2-iteration Blake2b-256 hashing
- Token verification logic
-
TokenAuthenticationFilter (
TokenAuthenticationFilter.java)- Extracts group_name from path
- Validates Authorization header
- Queries database for group_id
- Sets Spring Security context
-
SecurityConfig (
SecurityConfig.java)- Public endpoints (no auth): /api/create-group, /api/ge-prices, etc.
- Protected endpoints: /api/group/**
- Stateless session management
-
CorsConfig (
CorsConfig.java)- Configurable allowed origins
- Supports RuneLite plugin + frontend
🚧 Next Steps (In Order of Priority)
Phase 1A: Core Data Layer (CRITICAL)
1. JPA Entities
Files to create:
model/Group.javamodel/Member.javamodel/SkillDataDay.java,SkillDataMonth.java,SkillDataYear.javamodel/CollectionTab.java,CollectionPage.javamodel/CollectionLog.java,CollectionLogNew.java
Key Requirements:
- Use
@Type(JsonType.class)for array fields (Hibernate JSON support) - Map to MariaDB schema exactly
- Include all timestamp fields (*_last_update)
- Lombok annotations (@Data, @Entity, @Table)
2. Spring Data Repositories
Files to create:
repository/GroupRepository.javarepository/MemberRepository.javarepository/SkillDataRepository.javarepository/CollectionLogRepository.java
Key Methods:
// GroupRepository
Optional<Long> findGroupIdByNameAndTokenHash(String name, String hash);
Optional<Group> findByGroupName(String name);
// MemberRepository
List<Member> findByGroupIdAndLastUpdatedAfter(Long groupId, Instant timestamp);
Optional<Member> findByGroupIdAndMemberName(Long groupId, String name);
int countByGroupId(Long groupId);
Phase 1B: Service Layer
3. Business Logic Services
Files to create:
-
service/GroupService.javacreateGroup(CreateGroupRequest)→ Returns token + groupIdgetGroupData(groupId, fromTimestamp)→ Delta updates
-
service/MemberService.javaupdateMember(groupId, memberName, updateData)addMember(groupId, memberName)deleteMember(groupId, memberName)renameMember(groupId, oldName, newName)
-
service/SkillAggregationService.javaaggregateSkills(period)→ Scheduled taskapplyRetentionPolicy(period, maxAge)
-
service/GrandExchangeService.javafetchAndCachePrices()→ HTTP call to RuneScape Wiki APIgetCachedPrices()→ Return cached prices
-
service/CollectionLogService.javaupdateCollectionLog(memberId, collectionLogData)getCollectionLog(groupId)
Phase 1C: API Controllers
4. REST Controllers
Files to create:
-
controller/PublicController.javaPOST /api/create-group GET /api/ge-prices GET /api/captcha-enabled GET /api/collection-log-info -
controller/GroupController.javaGET /api/group/{group_name}/get-group-data?from_time=<timestamp> GET /api/group/{group_name}/am-i-logged-in GET /api/group/{group_name}/am-i-in-group -
controller/MemberController.javaPOST /api/group/{group_name}/update-group-member POST /api/group/{group_name}/add-group-member DELETE /api/group/{group_name}/delete-group-member PUT /api/group/{group_name}/rename-group-member -
controller/SkillController.javaGET /api/group/{group_name}/get-skill-data?period=<day|month|year> -
controller/CollectionLogController.javaGET /api/group/{group_name}/collection-log
5. DTOs (Data Transfer Objects)
Files to create:
dto/CreateGroupRequest.javadto/CreateGroupResponse.javadto/UpdateMemberRequest.javadto/GroupMemberResponse.javadto/SkillDataResponse.javadto/GePricesResponse.javadto/CollectionLogResponse.java
Critical: DTOs must match Rust JSON structure EXACTLY for plugin compatibility.
Phase 1D: Background Jobs
6. Scheduled Tasks
File to create:
service/ScheduledTasks.java@Scheduled(fixedRate = 14400000) // 4 hours public void updateGePrices() @Scheduled(fixedRate = 1800000) // 30 minutes public void aggregateSkills()
Phase 1E: Exception Handling
7. Custom Exceptions & Global Handler
Files to create:
exception/GroupNotFoundException.javaexception/MemberNotFoundException.javaexception/GroupFullException.java(max 5 members)exception/ValidationException.javaexception/GlobalExceptionHandler.java(@ControllerAdvice)
Phase 1F: Utilities
8. Helper Classes
Files to create:
-
util/ValidationUtils.javavalidateMemberName(name)→ Regex:[A-Za-z 0-9-_]{1,16}validateArrayLengths(member)→ Ensure correct array sizes
-
util/CollectionLogLoader.java- Load
collection_log_info.jsonat startup - Populate
collection_pagetable
- Load
🧪 Phase 2: Testing
Unit Tests
- Blake2TokenHasher test (verify matches Rust output)
- Service layer tests (Mockito)
- Repository tests (TestContainers + MariaDB)
Integration Tests
- Full API flow tests (create group → update member → get data)
- Authentication tests (valid/invalid tokens)
- CORS tests
Plugin Compatibility Tests
- Test with actual RuneLite plugin
- Verify JSON payload structure matches
- Test all plugin → server endpoints
📦 Phase 3: Deployment
Docker Configuration
Files to create:
Dockerfile(multi-stage build)docker-compose.yml(backend + MariaDB).dockerignore- Deployment scripts for Proxmox/Debian containers
Environment Variables
Required for production:
DB_HOST=<mariadb_host>
DB_PORT=3306
DB_NAME=groupironman
DB_USER=<user>
DB_PASSWORD=<password>
SERVER_PORT=8080
BACKEND_SECRET=<generate_strong_secret>
CAPTCHA_ENABLED=false
CORS_ORIGINS=https://yourfrontend.com
📋 Implementation Checklist
Critical Path (Must Complete for MVP)
- JPA Entities (Group, Member, SkillData, CollectionLog)
- Repositories (GroupRepository, MemberRepository)
- GroupService (createGroup, getGroupData)
- MemberService (updateMember, addMember)
- PublicController (createGroup, gePrices)
- GroupController (getGroupData)
- MemberController (updateMember)
- DTOs matching Rust JSON structure
- GrandExchangeService (fetch prices from Wiki API)
- ScheduledTasks (GE prices updater)
- Exception handling (@ControllerAdvice)
- Docker build & deployment config
Nice-to-Have (Post-MVP)
- Skill aggregation service
- Collection log features
- Captcha validation
- Metrics/monitoring (Spring Actuator)
- Comprehensive test suite
🐛 Known Challenges
1. Array Type Handling
Issue: MariaDB doesn't natively support arrays like PostgreSQL. Solution: Use JSON columns and custom Hibernate type converters.
Example:
@Type(JsonType.class)
@Column(name = "skills", columnDefinition = "json")
private List<Integer> skills; // 24 skills
2. Timestamp Precision
Issue: PostgreSQL TIMESTAMPTZ vs MariaDB TIMESTAMP
Solution: Use TIMESTAMP(6) for microsecond precision, convert to/from Instant in Java.
3. Blake2 Hashing Compatibility
Critical: Hash output MUST match Rust implementation exactly. Testing: Create unit test with known token/salt/hash triplets from Rust server.
4. JSON Payload Structure
Critical: Plugin expects specific JSON keys and types. Solution: Create DTOs that serialize EXACTLY as Rust structs.
Example from Rust:
GroupMember {
name: String,
stats: Option<Vec<i32>>, // null if not updated
skills: Option<Vec<i32>>,
// ...
}
Java DTO must output:
{
"name": "PlayerName",
"stats": [99, 99, 100, 301], // or null
"skills": [13034431, ...], // or null
"last_updated": "2024-01-01T12:00:00Z"
}
📞 Next Actions
- Immediate: Create JPA entities and repositories
- Then: Implement GroupService and MemberService
- Then: Create REST controllers with DTOs
- Test: Run Gradle build, start application, test endpoints with Postman
- Deploy: Create Docker image, test in container
- Plugin Test: Point RuneLite plugin to new backend, verify functionality
🔗 Related Documentation
- Rust Source:
group-ironmen-master/server/src/ - Database Schema:
group-ironmen-master/server/src/db.rs(lines 959-1170) - API Endpoints:
group-ironmen-master/server/src/authed.rs+unauthed.rs - Frontend Site:
group-ironmen-master/site/src/ - Collection Log Info:
group-ironmen-master/site/public/data/collection_log_info.json
Status: Phase 1A in progress (foundation complete, data layer next) Last Updated: 2025-10-27