internal/planning/MONOREPO_MERGER_PLAN.md
Version: 1.0 Date: 2025-09-24 Status: Planning Phase GitHub Issue: #1765
This document provides the complete implementation plan for merging the react_on_rails and react_on_rails_pro repositories into a unified monorepo while maintaining separate package identities and proper license compliance.
Estimated Duration: 5-6 weeks across 8 phases
react_on_rails/
├── lib/react_on_rails/ # Core Ruby (MIT)
├── node_package/src/ # Core JS/TS + pro/ subdirectory
├── spec/ # Tests
├── react_on_rails.gemspec # Core gem
├── .github/workflows/ # GitHub Actions CI
└── package.json # Core NPM package
react_on_rails_pro/
├── lib/react_on_rails_pro/ # Pro Ruby
├── packages/node-renderer/ # Pro Node renderer
├── spec/ # Pro tests
├── react_on_rails_pro.gemspec # Pro gem
├── .circleci/ # CircleCI CI
└── package.json # Pro NPM package
node_package/src/pro/react_on_rails/ (monorepo root)
├── lib/
│ ├── react_on_rails/ # Core Ruby (MIT)
│ │ └── spec/ # Core Ruby specs
│ └── react_on_rails_pro/ # Pro Ruby (Pro license)
│ └── spec/ # Pro Ruby specs
├── packages/ # NPM packages (pnpm workspaces)
│ ├── react-on-rails/ # Core JS/TS (MIT)
│ │ └── tests/ # Core JS/TS tests
│ ├── react-on-rails-pro/ # Pro JS/TS (Pro license)
│ │ └── tests/ # Pro JS/TS tests
│ └── react-on-rails-pro-node-renderer/ # Pro node renderer
│ └── tests/ # Pro node renderer tests
├── spec/ # Monorepo-level integration tests
│ └── dummy/ # Rails dummy app for testing
├── tools/ # Shared development tools
├── docs/ # Unified documentation
├── react_on_rails.gemspec # Core gem
├── react_on_rails_pro.gemspec # Pro gem
├── package.json # Workspace manager
├── Gemfile # Both gems
├── LICENSE.md # MIT license + pro exclusions
├── REACT-ON-RAILS-PRO-LICENSE.md # Pro license
└── README.md
Ruby Gems (2 separate):
react_on_rails gem (MIT License)react_on_rails_pro gem (Pro License, depends on react_on_rails)NPM Packages (3 separate):
react-on-rails (MIT License)react-on-rails-pro (Pro License, depends on react-on-rails)react-on-rails-pro-node-renderer (Pro License)Branch: prepare-licenses
Target: Both repositories (separate PRs)
Objectives:
Tasks:
react_on_rails_pro/LICENSE to reference v2.0 license consistentlySuccess Criteria: ✅ All existing CI checks pass + License compliance verified
Estimated Duration: 2-3 days
Developer Notes:
Branch: merge-pro-subtree-with-ci
Target: react_on_rails repository
Objectives:
Git Strategy:
⚠️ CRITICAL: Create feature branch FIRST before any work!
# 1. FIRST: Create and checkout feature branch
git checkout -b merge-pro-subtree-with-ci
# 2. Clone and prepare pro repository with filter-repo (better for file history browsing)
git clone https://github.com/shakacode/react_on_rails_pro.git /tmp/react_on_rails_pro
cd /tmp/react_on_rails_pro
git filter-repo --to-subdirectory-filter react_on_rails_pro
# 3. Add the prepared pro repo as remote and merge
cd /path/to/react_on_rails
git remote add pro-origin /tmp/react_on_rails_pro
git fetch pro-origin
git merge pro-origin/main --allow-unrelated-histories
# 4. Push branch and create PR
git push -u origin merge-pro-subtree-with-ci
Why filter-repo instead of subtree:
Tasks:
react_on_rails_pro/ directoryreact_on_rails_pro/ as Pro-licensedreact_on_rails_pro/ directoryExpected Directory Structure After Merge:
react_on_rails/ (root)
├── lib/react_on_rails/ # Original core
├── node_package/ # Original core JS
├── spec/ # Original core tests
├── react_on_rails.gemspec # Original core
├── package.json # Original core
├── .github/workflows/ # UPDATED - tests core
│
├── react_on_rails_pro/ # ADDED - Complete pro repo
│ ├── lib/react_on_rails_pro/
│ ├── packages/node-renderer/
│ ├── spec/
│ ├── react_on_rails_pro.gemspec
│ ├── package.json
│ └── .circleci/ # Keep temporarily
Updated LICENSE.md Section:
## React on Rails Pro License applies to:
- `react_on_rails_pro/` (entire directory)
All other files are licensed under MIT License.
After the initial merge, the following CI adjustments may be needed:
Success Criteria: ✅ ALL CI jobs pass for both core and pro packages independently
Estimated Duration: 2-3 days (with lessons learned above: 1-2 days)
Risk Level: High (first major structural change)
Developer Notes:
react_on_rails_pro/ directory is listed in LICENSE.md as Pro-licensedCritical Lessons Learned (Phase 2 Implementation):
git filter-repo --to-subdirectory-filter + git merge --allow-unrelated-histories instead of subtree for better file history browsing.rubocop.yml with 'react_on_rails_pro/**/*' exclusioneslint.config.ts with 'react_on_rails_pro/' exclusion.prettierignore with react_on_rails_pro/ exclusionknip.ts with 'react_on_rails_pro/**' in ignore patternspreinstall scripts to all package.json files that need local react-on-railslink-source scripts to build and publish packages with yalcfile: paths in package.json - use link:.yalc/package-name insteadreact_on_rails/spec/dummy/ (main dummy app)react_on_rails_pro/spec/dummy/ (pro dummy app)react_on_rails_pro/spec/execjs-compatible-dummy/ (ExecJS dummy app)path: "../.." in gemspec and development dependenciesyalc add --link package-name in preinstall hooksBranch: prepare-core-workspace
Objectives:
Tasks:
packages/react-on-rails/ directorynode_package/src/ to packages/react-on-rails/src/ (excluding pro/ subdirectory)packages/react-on-rails/package.json with correct configurationpackage.json to workspace manager (packages/react-on-rails only)node_package/lib/ to packages/react-on-rails/lib/)packages/react-on-rails/tests/react_on_rails_pro/ directory unchangedLicense Compliance:
CRITICAL: Verify NO pro files moved to MIT-licensed core package
Ensure packages/react-on-rails/src/ contains ONLY MIT-licensed code
Update LICENSE.md to reflect new paths:
## MIT License applies to:
- `lib/react_on_rails/`
- `packages/react-on-rails/` (new path)
## React on Rails Pro License applies to:
- `react_on_rails_pro/` (entire directory)
Success Criteria: ✅ All CI checks pass + No pro code in MIT directories + Workspace builds successfully
Estimated Duration: 2-3 days
Developer Notes:
packages/react-on-rails/, carefully verify that no pro files (especially from node_package/src/pro/) accidentally get moved to the MIT-licensed directorypackages/react-on-rails/ pathpackages/react-on-rails/lib/ instead of node_package/lib/Branch: split-js-pro-package
Objectives:
Tasks:
packages/react-on-rails/src/pro/ to packages/react-on-rails-pro/src/packages/react-on-rails-pro/package.json with "license": "UNLICENSED"packages/react-on-rails/tests/ to packages/react-on-rails-pro/tests/packages/react-on-rails-propackages/react-on-rails-pro/lib/)packages/react-on-rails/src/any typesLicense Compliance:
CRITICAL: Update LICENSE.md to remove pro code from MIT package:
## MIT License applies to:
- `lib/react_on_rails/` (entire directory)
- `packages/react-on-rails/` (entire package)
## React on Rails Pro License applies to:
- `packages/react-on-rails-pro/` (entire package)
- `react_on_rails_pro/` (entire directory)
Add Pro license headers to moved files
Verify react-on-rails-pro package has "license": "UNLICENSED" in package.json
Verify react-on-rails package no longer contains pro code
Success Criteria: ✅ All CI checks pass + Pro JS code cleanly separated + License boundaries established + Both NPM packages build independently
Estimated Duration: 3-4 days
Risk Level: Medium-High (complex file movements)
Developer Notes:
packages/react-on-rails-pro/ directory, immediately update LICENSE.md to include this new path"license": "UNLICENSED"packages/react-on-rails-pro/lib/Branch: add-pro-node-renderer
Objectives:
Tasks:
react_on_rails_pro/packages/node-renderer/ to packages/react-on-rails-pro-node-renderer/packages/react-on-rails-pro-node-renderer/package.json with "license": "UNLICENSED"packages/react-on-rails-pro-node-renderer/tests/packages/react-on-rails-pro-node-renderer/lib/)License Compliance:
CRITICAL: Update LICENSE.md for node-renderer package:
## React on Rails Pro License applies to:
- `lib/react_on_rails_pro/` (including specs)
- `packages/react-on-rails-pro/` (including tests)
- `packages/react-on-rails-pro-node-renderer/` (including tests) (NEW)
- `react_on_rails_pro/` (remaining files)
Verify node-renderer package has "license": "UNLICENSED" in package.json
Success Criteria: ✅ All CI checks pass + All 3 NPM packages build + Complete workspace structure established
Estimated Duration: 2-3 days
Risk Level: Medium (straightforward package extraction)
Developer Notes:
packages/react-on-rails-pro-node-renderer/lib/Branch: restructure-ruby-gems
Objectives:
Tasks:
react_on_rails_pro/lib/react_on_rails_pro/ to lib/react_on_rails_pro/react_on_rails_pro/react_on_rails_pro.gemspec to root as react_on_rails_pro.gemspeclib/react_on_rails/spec/ (or keep existing spec/ location)lib/react_on_rails_pro/spec/Gemfile to include both gemspecsreact_on_rails_pro/ directory.github/dependabot.yml to reflect final directory structure:
/react_on_rails_pro bundler entry (directory no longer exists)/react_on_rails to / (root now has both gemspecs)License Compliance:
Update LICENSE.md to final directory structure:
## MIT License applies to:
- `lib/react_on_rails/` (including specs)
- `packages/react-on-rails/` (including tests)
## React on Rails Pro License applies to:
- `lib/react_on_rails_pro/` (including specs)
- `packages/react-on-rails-pro/` (including tests)
- `packages/react-on-rails-pro-node-renderer/` (including tests)
Update both gemspec files with correct license:
# react_on_rails.gemspec
s.license = "MIT"
# react_on_rails_pro.gemspec
s.license = "UNLICENSED" # Pro license
Verify no pro files accidentally moved to MIT directories
Success Criteria: ✅ All CI checks pass + Final license structure verified + Both gems build from root
Estimated Duration: 2-3 days
Developer Notes:
react_on_rails_pro/lib/react_on_rails_pro/ to lib/react_on_rails_pro/, ensure you update the LICENSE.md path from the temporary location to the final locationspec/ruby/react_on_rails_pro/ and not spec/ruby/react_on_rails/Branch: unify-cicd
Objectives:
Decision Point: Choose Final CI System
Tasks:
pnpm test instead of separate pnpm test --filter calls in CI, to be more robust if packages need to be added/removedLicense Compliance:
license-check:
runs-on: ubuntu-latest
steps:
- name: Verify Pro License Headers
run: |
find lib/react_on_rails_pro packages/react-on-rails-pro* -name "*.rb" -o -name "*.js" -o -name "*.ts" | \
xargs grep -L "Pro License\|UNLICENSED" && exit 1 || echo "✅ All pro files properly licensed"
Success Criteria: ✅ All CI checks pass + Automated license enforcement in place + Single CI system operational
Estimated Duration: 2-3 days
Developer Notes:
Branch: update-docs-examples
Objectives:
Tasks:
packages/react-on-rails/README.mdpackages/react-on-rails-pro/README.mdpackages/react-on-rails-pro-node-renderer/README.mdLicense Compliance:
Document licensing clearly in main README.md:
## 📄 Licensing
This monorepo contains packages under different licenses:
### MIT Licensed (Free & Open Source):
- `react_on_rails` Ruby gem
- `react-on-rails` NPM package
- Core functionality in `lib/react_on_rails/` and `packages/react-on-rails/` (including tests/specs)
### Pro Licensed (Subscription Required for Production):
- `react_on_rails_pro` Ruby gem
- `react-on-rails-pro` NPM package
- `react-on-rails-pro-node-renderer` NPM package
- Pro functionality in `lib/react_on_rails_pro/` and `packages/react-on-rails-pro*/` (including tests/specs)
See [LICENSE.md](LICENSE.md) and [REACT-ON-RAILS-PRO-LICENSE.md](REACT-ON-RAILS-PRO-LICENSE.md)
Update individual package READMEs with appropriate license info
Create LICENSE.md symlinks in package directories if needed
Verify all examples respect license boundaries
Ensure example code with pro features is clearly marked
Success Criteria: ✅ All CI checks pass + Complete and accurate documentation + Migration guide available
Estimated Duration: 2-3 days
Developer Notes:
Directory Classification:
lib/react_on_rails/ (including specs), packages/react-on-rails/ (including tests)LICENSE.md Updates:
File Movement Verification:
Location: script/check-license-compliance.rb
#!/usr/bin/env ruby
# Script to verify license compliance across the monorepo
PRO_DIRECTORIES = %w[
lib/react_on_rails_pro
packages/react-on-rails-pro
packages/react-on-rails-pro-node-renderer
].freeze
MIT_DIRECTORIES = %w[
lib/react_on_rails
packages/react-on-rails
].freeze
def check_pro_license_headers
puts "🔍 Checking pro files have correct license headers..."
PRO_DIRECTORIES.each do |dir|
next unless Dir.exist?(dir)
files = Dir.glob("#{dir}/**/*.{rb,js,ts,tsx}")
files.each do |file|
content = File.read(file)
unless content.match?(/Pro License|UNLICENSED|React on Rails Pro/i)
puts "⚠️ WARNING: Pro file missing license header: #{file}"
end
end
end
puts "✅ Pro license headers verified"
end
def verify_license_md_accuracy
puts "🔍 Verifying LICENSE.md lists all pro directories..."
license_content = File.read('LICENSE.md')
PRO_DIRECTORIES.each do |dir|
next unless Dir.exist?(dir)
unless license_content.include?(dir)
puts "❌ CRITICAL: Pro directory not listed in LICENSE.md: #{dir}"
exit 1
end
end
puts "✅ LICENSE.md accurately lists all pro directories"
end
check_pro_license_headers
verify_license_md_accuracy
puts "🎉 License compliance check passed!"
license-compliance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run License Compliance Check
run: ruby script/check-license-compliance.rb
When directories are moved or renamed during the merger, the following configuration files must be updated to reflect the new structure:
| File | What to Update |
|---|---|
.github/dependabot.yml | directory: entries for bundler/npm ecosystems |
.rubocop.yml | Exclusion patterns |
eslint.config.ts | Ignore patterns |
.prettierignore | Ignored directories |
knip.ts | Ignore patterns |
The .github/dependabot.yml file configures automated security updates. It must be kept in sync with the repository structure.
Current Configuration (Pre-Phase 6):
# NPM entries
- directories:
- '/' # Root pnpm workspace
- '/react_on_rails/spec/dummy' # Open source dummy app
- '/react_on_rails_pro/spec/dummy' # Pro dummy app
# Bundler entries
- directories:
- '/react_on_rails' # Open source gem
- '/react_on_rails/spec/dummy' # Open source dummy app
- '/react_on_rails_pro' # Pro gem
- '/react_on_rails_pro/spec/dummy' # Pro dummy app
- '/react_on_rails_pro/spec/execjs-compatible-dummy' # ExecJS dummy app
# GitHub Actions
- directory: '/'
Final Configuration (Post-Phase 6):
# NPM entries (final dummy app locations may be different or they may become part of the workspace and be removed here)
- directories:
- '/' # Root pnpm workspace
- '/lib/react_on_rails/spec/dummy' # Open source dummy app
- '/lib/react_on_rails_pro/spec/dummy' # Pro dummy app
# Bundler entries (or other final dummy app locations)
- directories:
- '/' # Root now contains both gemspecs
- '/lib/react_on_rails/spec/dummy' # Open source dummy app
- '/lib/react_on_rails_pro/spec/dummy' # Pro dummy app
- '/lib/react_on_rails_pro/spec/execjs-compatible-dummy' # ExecJS dummy app
# GitHub Actions (unchanged)
- directory: '/'
When to Update dependabot.yml:
# Clone the monorepo
git clone https://github.com/shakacode/react_on_rails.git
cd react_on_rails
# Install dependencies
bundle install # Ruby gems
pnpm install # NPM packages (workspace)
# Build all packages
pnpm build # NPM packages
rake build:gems # Ruby gems
# Run tests
pnpm test # NPM package tests
bundle exec rspec spec/ruby # Ruby tests
# Development commands
pnpm --filter react-on-rails build # Build core package
pnpm --filter react-on-rails-pro test # Test pro package
cd packages/react-on-rails && pnpm dev # Development server
This document serves as the definitive context for implementing the React on Rails monorepo merger. AI agents working on this plan should:
This merger plan balances the benefits of a monorepo (shared tooling, unified development) with the need for separate packages (independent licensing, versioning, and distribution). The phased approach ensures CI safety and license compliance throughout the process.
The key to success is maintaining strict license boundaries while creating a unified development experience. Each phase has clear success criteria and rollback procedures to ensure the project never enters a broken state.
⚠️ Critical Success Factor: License compliance is not optional - every file movement must be accompanied by appropriate LICENSE.md updates and verification that no pro code enters MIT-licensed directories.