RODA (Repository of Authentic Digital Records) is an enterprise-grade digital preservation repository implementing the OAIS reference model. It handles ingestion, storage, indexing, and access to digital archival content using internationally recognized preservation standards (METS, EAD, Dublin Core, PREMIS, E-ARK).
Current Version: 6.1.0-SNAPSHOT
License: Apache 2.0
Package Namespace: org.roda.*
| Component | Technology | Version |
|---|---|---|
| Language | Java | 21 (Oracle JDK) |
| Build | Apache Maven | 3.8.6+ |
| Backend | Spring Boot | 3.5.x |
| Web UI | GWT | 2.12.2 |
| Search/Index | Apache Solr | 9.10.0 |
| Database | PostgreSQL | 17 |
| Actors | Pekko (Akka replacement) | 1.4.0 |
| Serialization | Jackson | 2.20.1 |
roda/
├── pom.xml # Root Maven POM — dependency management, profiles
├── code-style/
│ ├── checkstyle.xml # Enforced style rules
│ └── eclipse_formatter.xml # Java formatter (required for IntelliJ)
├── roda-common/
│ ├── roda-common-data/ # Shared POJOs: AIP, DIP, Representation, etc.
│ └── roda-common-utils/ # Shared utility classes
├── roda-core/
│ ├── roda-core/ # Core business logic
│ │ └── src/main/java/org/roda/core/
│ │ ├── common/ # PREMIS, email, Handlebars templates
│ │ ├── config/ # Spring Boot configuration
│ │ ├── entity/ # JPA/Hibernate entities
│ │ ├── events/ # Async event system
│ │ ├── index/ # Solr indexing services & filters
│ │ ├── migration/ # Schema/data migration logic
│ │ ├── model/ # CRUD for RODA objects (AIPs, DIPs)
│ │ ├── plugins/ # Preservation action plugin framework
│ │ ├── protocols/ # File transfer protocols
│ │ ├── repository/ # Repository service interfaces
│ │ ├── security/ # Auth, LDAP, permissions
│ │ ├── storage/ # Filesystem/cloud storage abstraction
│ │ └── transaction/ # Transaction logging
│ └── roda-core-tests/ # Test helpers, TestsHelper, CorporaConstants
├── roda-ui/
│ └── roda-wui/ # GWT web app + Spring Boot REST API
│ └── src/main/java/org/roda/wui/
│ ├── api/v1/ # Legacy REST endpoints
│ ├── api/v2/ # Current REST endpoints (OpenAPI)
│ ├── client/ # GWT client-side components
│ ├── common/ # Shared UI utilities
│ ├── config/ # Spring configuration
│ ├── filter/ # Security filters
│ ├── security/ # Authentication handlers
│ └── servlets/ # Custom servlet implementations
├── deploys/
│ └── standalone/
│ ├── docker-compose.yaml # Production-like setup
│ └── docker-compose-dev.yaml # Development setup
├── docker/ # Docker image build files
│ └── Dockerfile # eclipse-temurin:21-jre-jammy base
├── dev/
│ └── codeserver/ # GWT codeserver config for hot reload
├── scripts/ # Release and utility scripts
├── documentation/ # 100+ Markdown docs (multi-language)
├── openapi.json # REST API specification
└── .github/workflows/ # CI/CD pipelines
- Java 21 (Oracle JDK) — strictly required for compilation
- Maven 3.8.6+ — build tool
- Docker & Docker Compose — for running Solr, PostgreSQL, LDAP, etc.
- GitHub account with PAT — required for GitHub Packages dependency resolution
Configure Maven for GitHub Packages (~/.m2/settings.xml):
The easiest way is to set the environment variables and run the provided script:
export GITHUB_MAVEN_USER=YOUR_GITHUB_USERNAME
export GITHUB_MAVEN_PASSWORD=YOUR_GITHUB_PAT
./scripts/setup_maven_settings.shAlternatively, create ~/.m2/settings.xml manually:
<settings>
<servers>
<server>
<id>github</id>
<username>YOUR_GITHUB_USERNAME</username>
<password>YOUR_GITHUB_PAT</password>
</server>
</servers>
</settings>The PAT must have read:packages permission. Without this, the build will fail to resolve dependencies.
# Create required data directories
mkdir -p $HOME/.roda/data/{storage,staging-storage}
# Start all services (Solr, ZooKeeper, PostgreSQL, ClamAV, Siegfried, OpenLDAP, MailPit)
docker compose -f deploys/standalone/docker-compose-dev.yaml up -dServices and ports:
- ZooKeeper:
2181 - Apache Solr:
8983 - PostgreSQL:
5432 - OpenLDAP:
1389 - MailPit (SMTP):
1025 - Swagger UI:
8088
# Full build with tests
mvn clean package
# Build without tests (faster)
mvn clean package -Dmaven.test.skip=true
# Build core modules only (skip UI)
mvn clean package -Pcore
# Install core to local Maven repo
mvn install -Pcore -DskipTests
# First-time GWT compile (slow, ~5-10 min)
mvn -pl roda-ui/roda-wui -am gwt:compile -Pdebug-main -Dscope.gwt-dev=compile| Profile | Purpose |
|---|---|
| (default) | All modules |
-Pcore |
Core modules only (faster, skips GWT) |
-Pdebug-main |
GWT development/debugging mode |
-Proda-core-jar |
Produces shaded JAR |
-Proda-core-jar-docker |
Docker-ready shaded JAR |
- Full build with tests: ~10–15 minutes
- Build without tests: ~5–8 minutes
- Tests only: ~8–12 minutes
- First GWT compile: ~5–10 minutes
# 1. Install core to local repo
mvn install -Pcore -DskipTests
# 2. Start Spring Boot application
mvn -pl roda-ui/roda-wui -am spring-boot:run -Pdebug-main
# 3. (Optional) Start GWT codeserver for hot reload in a separate terminal
mvn -f dev/codeserver gwt:codeserver -DrodaPath=$(pwd)- App available at:
http://localhost:8080 - GWT codeserver UI:
http://127.0.0.1:9876/ - Activate GWT dev mode: Open RODA in browser, click "Dev Mode On" bookmark
- TestNG (not JUnit) for all Java tests
- Tag CI tests with
@Test(groups = "travis")
roda-core-tests does not need the docker-compose-dev.yaml stack manually started. Its testng.xml registers RodaContainersLifecycleListener, which provisions its own ephemeral Solr Cloud/ZooKeeper/PostgreSQL/etc. containers via Testcontainers for the JVM run and tears them down afterward. All that's required is a reachable Docker daemon (docker info). Manually starting the dev compose stack is only needed to run the app itself (spring-boot:run), not to run this module's tests — running both at once is safe, since Testcontainers uses independent container names/ports.
# All tests (Docker daemon must be reachable; infra is self-provisioned)
mvn clean test
# CI subset only (faster)
mvn -Dtestng.groups="travis" -Denforcer.skip=true clean org.jacoco:jacoco-maven-plugin:prepare-agent test
# Skip tests
mvn clean package -Dmaven.test.skip=trueRODA_CORE_SOLR_TYPE=CLOUD
SIEGFRIED_MODE=standalone
See .github/workflows/CI.yml for the full CI test environment configuration.
org.roda.core.TestsHelper— common test utilitiesorg.roda.core.CorporaConstants— test data constantsModelServiceTest,IndexServiceTest,StorageServiceTestIngestPluginTests,DisposalTests,PermissionsTest
Tests live in:
roda-core/roda-core-tests/src/main/java/org/roda/core/roda-ui/roda-wui/src/test/
- Formatter: Eclipse Code Formatter (
code-style/eclipse_formatter.xml) - Linter: Checkstyle (
code-style/checkstyle.xml) — enforced during Maven build - Import order:
java;javax;org;com; - Wildcard imports: disabled (threshold set to 9999 classes)
- Install plugin: "Adapter for Eclipse Code Formatter"
- Point formatter at
code-style/eclipse_formatter.xml - Set import thresholds (class count: 9999, static: 9999)
- Format with:
Code > Reformat File...→ "Only VCS changed text"
- Root package:
org.roda - Module packages:
org.roda.core.*,org.roda.wui.*,org.roda.common.* - Model objects (POJOs) live in
roda-common-data - REST endpoints follow versioned paths:
/api/v1/(legacy) and/api/v2/(current)
GWT Web UI (client-side)
↕ REST API (Spring MVC, /api/v2/)
Spring Boot Application (roda-wui)
↕ Service interfaces
Core Services (roda-core)
├── ModelService — CRUD for AIPs, DIPs, Representations
├── IndexService — Solr-backed search & filtering
├── StorageService — Filesystem/cloud storage abstraction
└── PluginService — Preservation action orchestration
↕ Pekko actors (async jobs)
Infrastructure
├── PostgreSQL — Transactions, JPA entities
├── Apache Solr — Indexing & search (Cloud mode)
└── LDAP/CAS — Authentication
- Factory pattern:
RodaCoreFactorybootstraps and provides all core services - Observer pattern: Index services observe model changes for automatic re-indexing
- Plugin architecture: Extensible plugins for preservation workflows
- Storage abstraction: OpenStack Swift-inspired storage interface
- Event-driven: Pekko actors for async, parallel preservation tasks
- Transactional wrapper:
TransactionalModelServiceadds transaction logging
RODA implements the OAIS standard:
- SIP — Submission Information Package (ingest)
- AIP — Archival Information Package (stored)
- DIP — Dissemination Information Package (access)
- v1 (legacy):
/api/v1/— maintained for backwards compatibility - v2 (current):
/api/v2/— fully documented via OpenAPI - OpenAPI spec:
openapi.jsonand served at/api/v2/openapi - Swagger UI (dev):
http://localhost:8088
- PostgreSQL 17 via Spring Data JPA + Hibernate
- DDL mode:
update(Hibernate auto-updates schema) - Default connection:
jdbc:postgresql://localhost:5432/roda_core_db - Credentials:
admin/roda(development defaults) - Schema init:
spring.sql.init.mode=always
| File | Trigger | Purpose |
|---|---|---|
CI.yml |
Every push | Tests + package build |
codeql-analysis.yml |
Schedule | Security scanning |
development.yml |
Push to dev branch | Dev deployment |
staging.yml |
Push to staging | Staging deployment |
release.yml |
Tag push | Production release |
mvn -Dtestng.groups="travis" -Denforcer.skip=true \
clean org.jacoco:jacoco-maven-plugin:prepare-agent testBefore releasing:
# Security vulnerability check
mvn com.redhat.victims.maven:security-versions:check
# Check for dependency updates
./scripts/check_versions.sh MINOR
mvn versions:display-dependency-updatesRelease workflow (example: releasing 2.2.0, next 2.3.0):
./scripts/release.sh 2.2.0
# Wait for GitHub Actions release.yml to succeed
# Review and publish the GitHub Release
./scripts/update_changelog.sh 2.2.0
./scripts/prepare_next_version.sh 2.3.0# Build local Docker image
cd docker && ./build.sh
# Production-like local stack
docker compose -f deploys/standalone/docker-compose.yaml up -d
# Development stack
docker compose -f deploys/standalone/docker-compose-dev.yaml up -d
# Access shell in running container
docker exec -it CONTAINER_ID /bin/bashBase image: eclipse-temurin:21-jre-jammy
When modifying a module, rebuild its dependents:
roda-common-data → roda-common-utils → roda-core → roda-wui
After changing roda-core, run mvn install -Pcore -DskipTests before building roda-wui to update the local Maven cache.
- Translation files:
roda-ui/roda-wui/src/main/resources/config/i18n/ - Format: Java
.propertiesfiles - Managed via Transifex (cloud translation platform)
- Supported languages: English, Portuguese, Swedish, Hungarian, Spanish, Croatian, German (Austria), and more
- See
documentation/Translation_Guide.mdfor translation workflow
| File | Purpose |
|---|---|
README.md |
Project overview, features, editions |
DEV_NOTES.md |
Quick-start for developers |
documentation/Developers_Guide.md |
Comprehensive development guide |
openapi.json |
REST API specification |
pom.xml |
Root Maven config with all dependency versions |
.github/workflows/CI.yml |
CI configuration and test environment |
deploys/standalone/docker-compose-dev.yaml |
Dev service stack |
-
GitHub Packages auth is required. Maven build will fail without a valid
~/.m2/settings.xmlwith a GitHub PAT havingread:packages. -
roda-core-testsprovisions its own test infra via Testcontainers (Solr Cloud, ZooKeeper, PostgreSQL, LDAP, etc.) — just make sure the Docker daemon is reachable (docker info). Do not manually startdocker-compose-dev.yamlfor this; it's only needed to run the app itself (spring-boot:run). -
Use the correct Maven profile.
- Skip UI/GWT: use
-Pcore - GWT dev mode: use
-Pdebug-main - Never mix profiles incorrectly.
- Skip UI/GWT: use
-
TestNG, not JUnit. All test annotations are
org.testng.*. Group CI tests with@Test(groups = "travis"). -
Multi-module dependency order. Changing
roda-common-dataorroda-corerequiresmvn installbefore building downstream modules. -
GWT compilation is slow. The first compile takes 5–10 minutes. For active UI development, use the codeserver (
mvn -f dev/codeserver gwt:codeserver) for hot reload. -
Code formatting is enforced. Checkstyle runs during every Maven build. Always apply the Eclipse formatter from
code-style/eclipse_formatter.xmlbefore committing. -
REST API has two versions. New endpoints go in
/api/v2/. Do not add business logic to/api/v1/(legacy). -
PREMIS metadata is mandatory. Every preservation action must record a PREMIS event in the AIP's metadata. Follow existing plugin implementations as examples.
-
Commit signing. Commits should be GPG-signed per the project's contribution guidelines. See: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits