This file provides guidance for AI assistants and developers working with the openEQUELLA codebase.
It is the single source of truth, shared by every AI coding agent — vendor-specific entry points such
as CLAUDE.md reference this file rather than duplicating it.
For developers: This document offers a comprehensive architectural overview and coding conventions reference. For detailed development environment setup and contribution workflow, please refer to CONTRIBUTING.md.
openEQUELLA is a digital repository platform that provides a single platform to house teaching and learning, research, media, and library content. It is primarily developed and maintained by Edalex.
Key Characteristics:
- Runs on Java 21
- Runs within an embedded Tomcat server
- Supports Linux and Windows platforms
- Uses a hybrid architecture with both modern and legacy code
- Development primarily done in IntelliJ IDEA
Languages:
- Scala - Preferred for all new server-side code (Scala 2.13)
- Java - Used in legacy code and some specific contexts
- Mix of both throughout the codebase
Frameworks & Libraries:
- Guice - Primary dependency injection framework (use
@Injectannotations) - Spring - Used for supporting functions (less common than Guice)
- JPF (Java Plugin Framework) - Customized plugin system that structures the application into modules
- Hibernate - ORM for database persistence
- JAX-RS - REST endpoint definitions (use
@Pathannotations) - Apache Lucene - File-based search index for content and ACL resolution
Databases:
- PostgreSQL (recommended for development)
- MS SQL Server
- Oracle
New UI (Modern):
- TypeScript - All new UI code
- React (v19.x) - UI framework
- Material-UI (MUI) (v7.x) - Component library (
@mui/material) - fp-ts - Functional programming utilities
- io-ts - Runtime type validation
- Located in
react-front-end/directory - REST communication handled by
oeq-ts-rest-api/module
Legacy UI:
- Sections Framework - Bespoke Java-based web framework
- Freemarker - HTML templating (
.ftlfiles) - Legacy JavaScript - AJAX functionality in older pages
- Being gradually migrated to New UI
Admin Console:
- Java Swing application (standalone)
- Being migrated to New UI
Primary Build Tool: SBT
- Main build configuration in
build.sbt - Extensive customization via SBT plugins in
project/directory - Custom AutoPlugins handle JPF-specific tasks:
JPFScanPlugin- Scans for plugin projectsJPFPlugin- Default settings for JPF pluginsJPFRunnerPlugin- Collects plugins for deployment/running
- Run
./sbtfrom project root
Frontend Build:
- NPM - Package management (Node 24.11.0)
- Vite(v8.x) - Bundler for TypeScript/React code
- Build commands in
react-front-end/package.json
JPF Plugins:
- Each plugin has a
plugin-jpf.xmldescriptor file - Defines plugin dependencies and exports
- SBT automatically discovers and processes these
When writing or modifying code:
- Follow Clean Code principles
- Prefer declarative over imperative idioms
- Use pragmatic functional programming patterns where appropriate
- Leverage modern language features (Scala 2.13, Java 21, ES2020+)
- Match conventions in similar existing code
- Document complex logic with clear comments
- Add ScalaDoc/JavaDoc/JSDoc for public APIs
Scala:
- Preferred for all new server-side code
- Use functional programming patterns (immutability, pure functions, etc.)
- Leverage Scala collections and for-comprehensions
- Follow conventions in existing Scala code
Java:
- Use for specific contexts or when maintaining existing Java code
- Follow modern Java practices (streams, Optional, etc.)
- Consider refactoring to Scala when making substantial changes
TypeScript:
- Required for all new UI code
- Use strict type checking
- Leverage fp-ts for functional patterns
- Use io-ts for runtime type validation
- Prefer functional components with hooks in React
All code must be formatted using these tools:
| Language | Tool | Files | Configuration |
|---|---|---|---|
| Scala | ScalaFmt | *.scala, *.sbt |
.scalafmt.conf (v3.11.4) |
| Java | Google Java Format | *.java |
Run via google-java-format |
| TypeScript/JavaScript | ESLint + Prettier | *.ts, *.tsx, *.js |
eslint.config.mjs |
| CSS/SCSS | Prettier | *.css, *.scss |
Prettier defaults |
Pre-commit Hooks:
- Install with
npm ciin project root - Automatically formats staged files before commit
- Uses
huskyandlint-staged(seepackage.json)
Manual Formatting:
npm run format # Format all code
npm run format:scala # Scala only
npm run format:java # Java only
npm run format:ts # TypeScript onlyValidation:
npm run check # Check all formatting- Follow Conventional Commits specification
- Format:
<type>(<scope>): <description> - Types: feat, fix, docs, style, refactor, test, chore
- Enforced via
@commitlint/config-conventional
Backend Code:
Source/
├── Plugins/ # JPF plugin modules
│ ├── Core/ # Core plugins (most business logic)
│ │ └── com.equella.core/ # Main core plugin
│ ├── Platform/ # Platform-level plugins
│ ├── Extensions/ # Extension plugins
│ ├── Admin/ # Admin console related
│ └── RemoteRepositories/ # Remote repo integrations
├── Server/
│ ├── equellaserver/ # Server bootstrap and entry point
│ ├── adminTool/ # Admin console launcher
│ └── conversion/ # Conversion service
├── Reporting/ # BIRT reporting
├── Themes/ # UI themes
└── Tools/ # Utility tools
Frontend Code:
UI:
react-front-end/ # New UI React application
├── tsrc/ # TypeScript source
├── __tests__/ # Jest tests
└── __stories__/ # Storybook stories
REST client:
oeq-ts-rest-api/ # REST API client module
├── src/ # TypeScript REST client code
├── gen-io-ts/ # TypeScript project that generates io-ts codecs from src/ interfaces
│ # for runtime validation of server responses
└── test/ # REST client API tests (validate client API, not REST API itself)
Note: Tests in oeq-ts-rest-api/test/ validate the REST client's API (including type
validation), not the actual REST API endpoints. Testing of the REST API itself is done in the
autotest project.
Testing:
autotest/
├── src/test/java/ # Tests, the com.tle.webtests framework, and Page Objects
├── src/test/scala/ # Newer test code being written in Scala
├── institutions/ # Institution fixtures, imported by `sbt setupForTests`
├── suites/ # TestNG suite definitions
├── config/ # Autotest configuration (HOCON)
└── IntegTester/ # Support services the tests start up
autotest has one sbt configuration per test framework — test runs the TestNG suites and
ScalaTest/test runs the ScalaTest ones. ScalaTest is where new tests should go.
Build & Configuration:
project/ # SBT build customization
├── Common.scala
├── JPFPlugin.scala
├── JPFScanPlugin.scala
└── JPFRunnerPlugin.scala
Dev/
└── learningedge-config/ # Development configuration (generated)
build.sbt # Main SBT build file
package.json # Root NPM configuration
Adding New UI Features:
- Work in
react-front-end/tsrc/ - Add REST client methods in
oeq-ts-rest-api/src/ - Write tests for REST client methods in
oeq-ts-rest-api/src/test - Write Jest tests in
react-front-end/__tests__/ - Consider Storybook stories in
react-front-end/__stories__/
Adding REST Endpoints:
- Create in
Source/Plugins/Core/com.equella.core/(typically insrc/.../api/packages) - Use JAX-RS annotations (
@Path,@GET,@POST, etc.) - Add service layer in appropriate package
- Reference existing REST resources for patterns
Modifying Legacy UI:
- Java code in
Source/Plugins/using Sections framework - Freemarker templates (
.ftl) inresources/view/directories - Legacy JavaScript in
Source/Plugins/Core/com.equella.core/resources/web/js/
Adding Backend Business Logic:
- Write new code in Scala
- Use Guice for dependency injection
- Add unit tests (ScalaTest preferred)
Database Changes:
- Use Hibernate entities
- Consider migration scripts for schema changes
- Consider data migration for Export/Import files changes (e.g.backward-compatible import)
- Support all three databases (Postgres, MS SQL, Oracle)
Follow the testing pyramid - lots of unit tests, fewer integration tests, very few end-to-end tests:
- Unit Tests - Test individual classes/functions in isolation
- Integration Tests - Test interactions between components
- End-to-End Tests - Test complete user workflows (Selenium)
Unit Tests:
- Use ScalaTest for Scala code
- Use JUnit for Java code
- Mock external dependencies (Mockito available)
- Test business logic thoroughly
Integration Tests:
- Located in
autotest/IntegTester/ - Test REST endpoints
- Use TestNG
Unit/Component Tests:
- Use Jest and React Testing Library
- Located in
react-front-end/__tests__/ - Test component behaviour and user interactions
- Mock API calls
Running Tests:
cd react-front-end
npm run testPurpose:
The oeq-ts-rest-api/test/ directory contains tests that validate the REST client's API and
functionality, not the actual REST API endpoints themselves. These tests ensure:
- REST client methods work correctly
- Type definitions are accurate
- io-ts runtime type validation properly validates server responses
- Client API contracts are maintained
Key Points:
- Located in
oeq-ts-rest-api/test/ - Use Jest as the test framework
- Focus on client-side API behavior and type safety
- Validate that io-ts codecs (generated in
oeq-ts-rest-api/gen-io-ts/) correctly validate server responses - Require a running openEQUELLA instance to execute (tests make real HTTP calls)
Running Tests:
cd oeq-ts-rest-api
npm testPrerequisites:
Before running these tests, ensure you have:
- A running openEQUELLA instance (typically via
./sbt compile equellaserver/run) - Proper configuration pointing to your test instance
Note: For testing the actual REST API endpoints themselves (server-side behavior), use the
integration tests in autotest/IntegTester/.
Location: autotest/
Critical: Locator Strategy
Always follow this priority order when writing Selenium locators to ensure accessibility and reduce flakiness:
| Priority | Locator Type | Examples | Why? |
|---|---|---|---|
| 1. Semantic/ARIA | [aria-label], [role], [title] |
By.cssSelector("[aria-label='Submit']") |
Best Practice. Mimics screen readers. If this breaks, accessibility is broken. |
| 2. Test IDs | [data-testid] |
By.cssSelector("[data-testid='login-button']") |
Most Reliable. Dedicated QA hooks that don't change with CSS/layout. |
| 3. Text Content | linkText, partialLinkText |
By.linkText("Submit") |
User-Centric. Users look for text. Fragile with i18n. |
| 4. Unique IDs | By.id |
By.id("submit-btn") |
Fast Performance. Often missing or auto-generated in modern frameworks. |
| 5. CSS Selectors | By.cssSelector |
By.cssSelector(".main-nav .login-btn") |
Structural. Keep selectors short and specific. |
| 6. XPath | By.xpath |
By.xpath("//button[text()='Submit']") |
Last Resort. Only for complex parent-child traversals CSS cannot handle. |
Guidelines:
- Never use XPath unless absolutely necessary
- Use Page Object pattern (see existing Page Objects in
autotest/src/.../pageobject/) - Write tests that are robust to timing issues (proper waits, not sleeps)
- Reduce flakiness by using explicit waits and stable locators
- Match patterns in existing tests
Running Selenium Tests:
- TestNG suite definitions in
autotest/suites/ - Requires running openEQUELLA instance
- See
autotest/README.mdfor test organisation and how to run them
Core:
- Java 21 (Temurin via SDKMAN recommended)
- Node.js 24.11.0 (use NVM -
.nvmrcprovided) - PostgreSQL (or MS SQL/Oracle)
- ImageMagick
- FFmpeg
IDE:
- IntelliJ IDEA (recommended and used by all current developers)
- Increase heap to 4GiB for SBT build
- Enable plugins: Scala, TypeScript, Gradle
- Import as SBT project
Initial Setup:
./sbt prepareDevConfig # Generate dev configuration
./sbt compile # Compile everything
cd react-front-end && npm ci && npm run dev # Build New UIRunning Server:
./sbt compile equellaserver/runRunning Admin Console:
./sbt compile adminTool/runBuilding Installer:
./sbt installerZipFrontend Development:
cd react-front-end
npm run dev # Watch and rebuild
npm run storybook # Launch StorybookUpdating Plugin Libraries (Dev Mode):
./sbt jpfWriteDevJarsFull clean rebuild:
When changing branches or making significant changes, do a full clean rebuild to avoid stale artefacts:
./sbt devrebuildThis even rebuilds the New UI frontend from scratch. And triggers a build of the REST client and the io-ts codecs.
When working with integration features, be aware of:
- LMS Integration - LTI support (Moodle, Canvas, Brightspace)
- Authentication - OIDC, LDAP, OAuth providers
- Reporting - BIRT with custom connectors
- Search - Apache Lucene indexing
- Setup Guide:
CONTRIBUTING.md- Detailed development environment setup - Project Overview:
README.md- High-level project information - Release Process:
RELEASING.md- Release procedures - Build Configuration:
build.conf- CI build customisation
When contributing:
- Study similar existing code for patterns and conventions
- Use consistent naming (e.g., match package structure, file organisation)
- Follow the existing module/plugin organisation
- Maintain consistency with error handling patterns
- Use logging appropriately (SLF4J on backend)
- Handle i18n properly (language bundles in New UI)
- Consider accessibility in all UI changes
- Write tests that match existing test patterns
This document is intended to help AI assistants and new developers understand the openEQUELLA codebase. For detailed setup instructions, always refer to CONTRIBUTING.md.