9.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
OpenTripPlanner (OTP) is an open source multi-modal trip planner focusing on travel by scheduled public transportation combined with bicycling, walking, and mobility services. This is OTP2 (dev-2.x branch), the second major version under active development.
Tech Stack: Java 21, Maven, GraphQL API, GTFS/NeTEx transit data, OpenStreetMap
Essential Build Commands
# Build project and run tests
mvn package
# Build without running tests
mvn package -DskipTests
# Run tests
mvn test
# Run tests with code coverage
mvn jacoco:prepare-agent test
# Run integration tests (tagged with @Tag("integration"))
mvn test -Pit
# Build the shaded JAR (unified JAR with all dependencies)
# Output: otp-shaded/target/otp-shaded-VERSION.jar
mvn package
# Skip prettier formatting during build (useful for faster builds)
mvn test -Dps
# Clean test snapshots (for regenerating API/itinerary snapshot tests)
mvn clean -Pclean-test-snapshots
Code Formatting & Quality
# Prettier formats Java code automatically during build (validate phase)
# Configuration: .prettierrc.yml (100 char width, 2 space indent)
# To check formatting (used in CI)
mvn prettier:check
# Spotless removes unused imports
# Runs automatically during build (validate phase)
Running OTP
Main class: org.opentripplanner.standalone.OTPMain
# Run from IDE: Set main class and JVM args -Xmx2G
# Run from JAR: java -Xmx2G -jar otp-shaded/target/otp-shaded-VERSION.jar [args]
Testing
- Unit tests: JUnit 5, organized by package structure
- Integration tests: Use
-Pitprofile, tagged with@Tag("integration") - Snapshot tests: API and itinerary tests use
.snapfiles stored in git - Speed tests: Located in
test/performance/, run after each PR merge - Test data: Use smallest possible OSM extracts (see
doc/user/Preparing-OSM.md)
# Run a single test class
mvn test -Dtest=ClassName
# Run specific test method
mvn test -Dtest=ClassName#methodName
# Speed test (requires pre-built graph)
mvn exec:java -Dexec.mainClass="org.opentripplanner.transit.speed_test.SpeedTest" \
-Dexec.classpathScope=test -Dexec.args="--dir=test/performance/norway -p md -n 4 -i 3 -0"
Architecture Overview
Module Structure
OTP is a multi-module Maven project:
- application: Main OTP application code
src/main/java/org/opentripplanner/- Core source- Key packages:
routing,transit,street,gtfs,netex,apis,updater
- raptor: Transit routing engine (isolated, zero dependencies on OTP)
- utils: Utility classes
- gtfs-realtime-protobuf: GTFS-RT protocol buffer definitions
- otp-shaded: Produces unified JAR with all dependencies
- test/integration: Integration tests
Key Components
Transit Routing (Raptor)
- Location:
raptor/src/main/java/org/opentripplanner/raptor/ - The core transit routing algorithm, based on the Raptor paper (Microsoft 2012)
- Implements Range Raptor with multi-criteria pareto-optimal search
- Completely isolated from OTP - no dependencies on OTP code, only utility classes
- Performance-critical: test all changes with SpeedTest
- OTP provides data via SPI in
raptor/spi RoutingServicemaps between OTP domain and Raptor'sRaptorRequest/RaptorPath
Graph Building
- GTFS import:
application/src/main/java/org/opentripplanner/gtfs/ - NeTEx import:
application/src/main/java/org/opentripplanner/netex/ - OSM processing:
application/src/main/java/org/opentripplanner/osm/ - Graph builder:
application/src/main/java/org/opentripplanner/graph_builder/
Routing Components
- Routing algorithm:
application/src/main/java/org/opentripplanner/routing/algorithm/ - Transfer optimization:
routing/algorithm/transferoptimization/ - Itinerary filter chain:
routing/algorithm/filterchain/ - Street routing (A*):
application/src/main/java/org/opentripplanner/astar/
APIs
- GraphQL API:
application/src/main/java/org/opentripplanner/apis/ - GTFS GraphQL schema: Documented at http://localhost:8080/graphiql
- Real-time updaters:
application/src/main/java/org/opentripplanner/updater/
Configuration
- Location:
application/src/main/java/org/opentripplanner/standalone/config/ - Loads and parses JSON config files into POJOs
- Config types: build-config.json, router-config.json, otp-config.json
Design Model
OTP follows a layered architecture:
- Use Case Services: Stateless services combining multiple domain services
- Domain Services: Business logic for specific domains (transit, vehicle position, etc.)
- Domain Models: Encapsulate business areas with separate Service and Repository
- Repositories: Maintain domain models, used by updaters
Each documented component has a package.md file in its source directory.
Development Guidelines (from DEVELOPMENT_DECISION_RECORDS.md)
Code Quality
- Scout Rule: Leave code better than you found it
- Follow naming conventions from GTFS, NeTEx, or existing OTP code
- Write JavaDoc for all public types, methods, and fields
- Document business intention and decisions, not just logic
- Respect OOP principles: encapsulation, single responsibility, abstraction
- Avoid feature envy and code duplication (DRY)
Architecture
- Use dependency injection (manual DI or Dagger)
- Module wiring goes in
<module-name>/configure/<Module>Module.java - Keep modules isolated with
api,spi, and mapping layers - Avoid circular dependencies
Types
- Prefer immutable types over mutable
- Use builders where appropriate
- Be careful with records - only if proper encapsulation is possible
Testing
- Full branch test coverage preferred for non-trivial code
- Unit tests for all business logic
- Keep integration/system tests to a minimum
- Test at the lowest practical level
Code Style
- Prettier formats code automatically (enforced in CI)
- Spotless removes unused imports
- Line width: 100 characters, 2-space indent
Contribution Process
- Discuss changes in Gitter chat or developer meetings (twice weekly)
- Create GitHub issue for non-trivial changes
- Reference issue in PR with "addresses #123"
- PR requires 2 approvals from different organizations
- All tests must pass, code must compile
- Participate in developer meetings for faster PR progress
Important: This is an established project with high code quality expectations. Significant changes require discussion, documentation, and organizational commitment to maintenance.
Git Workflow
IMPORTANT: Protected Branches
- NEVER push directly to these branches:
dev-2.x,main,master,main_config - Always use feature branches for development work
- When asked to push changes, always ask which remote to use before pushing
- Ask witch remote a feature branches should be pushed to for creating PRs to upstream
Branch Structure:
- Main development branch:
dev-2.x - Release branch:
master(releases only, fast-forward merges from dev-2.x) - All changes via pull requests with code review
- Use Gitflow-derived branching model
- Break large changes into smaller PRs tied together with an "epic issue"
Creating Pull Requests:
- Create a feature branch (e.g.,
my-feature) - Make commits on the feature branch
- Ask witch remote to push the feature branch to:
git push -u entur my-feature - Create PR in upstream repository (
opentripplanner/OpenTripPlanner) usinggh pr create --repo opentripplanner/OpenTripPlanner --head entur:my-feature --base dev-2.x
Documentation
- User docs:
doc/user/(Markdown, built with MkDocs) - Architecture docs:
ARCHITECTURE.md, variouspackage.mdfiles - Developer guide:
doc/user/Developers-Guide.md - Decision records:
DEVELOPMENT_DECISION_RECORDS.md - Generated docs: https://docs.opentripplanner.org/
# Build docs locally
pip install -r doc/user/requirements.txt
mkdocs serve
Performance Testing
Performance is critical. The SpeedTest runs automatically after each merged PR.
# Run speed test locally (requires pre-built graph in test/performance/<location>)
mvn exec:java -Dexec.mainClass="org.opentripplanner.transit.speed_test.SpeedTest" \
-Dexec.classpathScope=test -Dexec.args="--dir=test/performance/norway -p md -n 4 -i 3 -0"
Dashboard: https://otp-performance.leonard.io/
Critical: All changes to Raptor must be tested with SpeedTest to ensure no performance regression.
Project Structure Notes
- Maven multi-module project
- Java 21 target
- Serialization version ID tracked in
pom.xmlpropertyotp.serialization.version.id - Shaded JAR output:
otp-shaded/target/otp-shaded-VERSION.jar - Client code:
client/src/(MapLibre-based JavaScript client for testing)
Key Dependencies
- Jersey (REST framework)
- Jackson (JSON)
- GeoTools (geospatial operations)
- JTS Topology Suite (geometry)
- Google Dagger (dependency injection)
- JUnit 5, Mockito, Google Truth (testing)
- Lucene (search indexing)
- Micrometer (metrics)
- Protocol Buffers (GTFS-RT)
Sandbox Features
Features not yet part of core OTP can be developed as Sandbox extensions. These must:
- Be in their own package
- Use feature flags (disabled by default)
- Have conditional code blocks in core OTP
- See: http://docs.opentripplanner.org/en/latest/SandboxExtension/