Note for developers: You can create
AGENTS.local.md(orCLAUDE.local.md) in this directory to add your own custom instructions or preferences for AI coding agents. These files are git-ignored and will not be committed to the repository.
OpenProject is a web-based, open-source project management software written in Ruby on Rails with PostgreSQL for data persistence.
- Size: Large monorepo (~840MB, ~1M+ lines of code)
- Backend: Ruby 3.4.7, Rails ~8.0.3
- Frontend: Node.js 22.21.0, npm 10.1.0+, TypeScript
- Database: PostgreSQL (required)
- Architecture: Server-rendered HTML with Hotwire (Turbo + Stimulus). Legacy Angular components exist and are being migrated to custom elements. Uses GitHub's Primer Design System via ViewComponent.
- Editions: Community, Enterprise (SSO, LDAP, SCIM), and BIM (construction industry, code in
modules/bim/)
ALWAYS verify versions before building:
- Ruby:
3.4.7(see.ruby-version) - Node:
^22.21.0(seepackage.jsonengines) - Bundler: Latest 2.x
OpenProject supports two development setups: Local and Docker. Choose one based on your preference.
bundle install # Install Ruby gems
cd frontend && npm ci && cd .. # Install Node packages
bundle exec rails db:migrate # Setup database
bin/dev # Start all services (Rails, frontend, Good Job worker)
# Access at http://localhost:3000The Docker development environment uses configurations in docker/dev/ and the bin/compose wrapper script.
# Initial setup (first time only)
bin/compose setup # Installs backend and frontend dependencies
# Starting services
bin/compose start # Start backend and frontend in background
bin/compose run # Start frontend in background, backend in foreground (for debugging with pry)
# Running tests
bin/compose rspec spec/models/user_spec.rb # Run specific tests in backend-test container
# Other operations
bin/compose reset # Remove all containers and volumes (requires setup again)
bin/compose <command> # Pass any docker-compose command directlyImportant Docker Notes:
- CRITICAL:
config/database.ymlmust NOT exist when using Docker (rename or delete it) - Most developers use a local
docker-compose.override.ymlfor custom port mappings and configurations - Copy
docker-compose.override.example.ymltodocker-compose.override.ymland customize as needed - Default ports: Backend at http://localhost:3000 (or 4200 for frontend dev server)
- Services:
backend,frontend,worker,db,db-test,backend-test,cache - Persisted volumes:
pgdata,bundle,npm,tmp,opdata(data survives container restarts) - Docker build context: Uses Dockerfiles in
docker/dev/backend/anddocker/dev/frontend/
app/- Rails application codeapp/components/- ViewComponent-based UI components (Ruby + ERB)app/contracts/- Validation and authorization contractsapp/controllers/- Rails controllersapp/models/- ActiveRecord modelsapp/services/- Service objects (business logic)app/workers/- Background job workers
config/- Rails configuration, routes, localesdb/- Database migrations and seedsfrontend/src/- Frontend codefrontend/src/app/- Legacy Angular modules/componentsfrontend/src/stimulus/- Stimulus controllersfrontend/src/turbo/- Turbo integration
lib/- Ruby libraries and extensionslookbook/- ViewComponent previews (https://qa.openproject-edge.com/lookbook/)modules/- OpenProject plugin modulesspec/- RSpec test suitespec/features/- System/feature tests (Capybara)spec/models/- Model unit testsspec/requests/- API/integration testsspec/services/- Service tests
.ruby-version- Ruby version.rubocop.yml- Ruby linting rules.erb_lint.yml- ERB template lintingfrontend/eslint.config.mjs- JavaScript/TypeScript lintingGemfile- Ruby dependenciespackage.json/frontend/package.json- Node.js dependencieslefthook.yml- Git hooks configuration
# Ruby
bundle exec rubocop # Check all files
bin/dirty-rubocop --uncommitted # Check only uncommitted changes
# JavaScript/TypeScript
cd frontend && npx eslint src/ && cd ..
# ERB Templates
erb_lint {files}
# Install Git Hooks (recommended)
bundle exec lefthook install# Backend (RSpec) - prefer specific tests over running all
bundle exec rspec spec/models/user_spec.rb # Single file
bundle exec rspec spec/models/user_spec.rb:42 # Single line
bundle exec rspec spec/features # Directory
bundle exec rake parallel:spec # Parallel execution
# Frontend (Jasmine/Karma)
cd frontend && npm test && cd .../script/github_pr_errors | xargs bundle exec rspec # Run failed tests from CI
./script/bulk_run_rspec spec/path/to/flaky_spec.rb # Run tests multiple times- Follow Ruby community style guide
- Use service objects for complex business logic (return
ServiceResult) - Use contracts for validation and authorization
- Keep controllers thin, models focused
- Document with YARD
- Write RSpec tests for all new features
- New development: Use Hotwire (Turbo + Stimulus) with server-rendered HTML
- Legacy code: Follow ESLint rules
- Prefer TypeScript over JavaScript
- Use Primer Design System via ViewComponent
- Use ERB for server-rendered views
- Use ViewComponents for reusable UI (with Lookbook previews)
- Lint with erb_lint before committing
- Follow Rails migration conventions
- Migrations are "squashed" between major releases (see
docs/development/migrations/)
- UI strings must use translation keys (never hard-coded)
- Source translations in
**/config/locales/en.ymlcan be modified directly - Other translations managed via Crowdin
- First line: < 72 characters, then blank line, then detailed description
- Reference work packages when applicable
- Merge strategy: "Merge pull request" (not squash), except single-commit PRs can use "Rebase and merge"
# Setup
bin/setup # Initial Rails setup
bin/setup_dev # Full dev environment setup
# Database
bundle exec rails g migration MigrationName # Generate a migration
bundle exec rails db:migrate # Run migrations
bundle exec rails db:rollback # Rollback last migration
bundle exec rails db:seed # Seed sample data
# Development
bin/dev # Start all services
bundle exec rails console # Rails console
bundle exec rails routes # List routes
# Testing
bundle exec rspec # Run RSpec tests
bundle exec rails parallel:spec # Parallel tests
cd frontend && npm test # Frontend tests
# Linting
bundle exec rubocop # Ruby linting
cd frontend && npx eslint src/ # JS/TS linting
erb_lint {files} # ERB linting# Setup and lifecycle
bin/compose setup # Setup Docker environment (first time)
bin/compose start # Start all services in background
bin/compose run # Start frontend in background, backend in foreground
bin/compose reset # Remove all containers and volumes
bin/compose stop # Stop all services
bin/compose down # Stop and remove containers
# Testing
bin/compose rspec spec/models/user_spec.rb # Run specific tests
bin/compose exec backend bundle exec rspec # Run tests directly in backend container
# Development
bin/compose exec backend bundle exec rails console # Rails console
bin/compose logs backend # View backend logs
bin/compose logs -f backend # Follow backend logs
bin/compose ps # List running containers
# Database
bin/compose exec backend bundle exec rails db:migrate # Run migrations
bin/compose exec backend bundle exec rails db:seed # Seed data
# Direct docker-compose commands
bin/compose up -d # Start services
bin/compose restart backend # Restart backend servicedocs/development/- Development documentationdocs/development/running-tests/- Testing guidedocs/development/code-review-guidelines/- Code review standardsCONTRIBUTING.md- Contribution workflow.github/copilot-instructions.md- Extended agent instructions with troubleshooting