Skip to content

Engine Contribution Guide (ERP Plus)

This document defines the official rules for creating, modifying, and maintaining Rails Engines inside ERP Plus.


Core Philosophy

Each engine in ERP Plus is:

a bounded domain module with strict ownership, clear interfaces, and zero hidden coupling.

Engines are NOT folders.

They are mini-products inside the system.


Engine Types

Engine Responsibility
erp_core Shared domain primitives (minimal logic), Authentication & identity
erp_accounts Tenancy + organizations
erp_users manage
erp_workers Background jobs
erp_inventory Stock & operations

Engine Rules (NON-NEGOTIABLE)

Every engine MUST:

  • be isolated
  • avoid internal dependencies from other engines
  • expose only public interfaces
  • be independently testable
  • respect multi-tenancy boundaries

Forbidden Patterns

Engines MUST NOT:

  • call internal models of another engine
  • share business logic directly
  • bypass service layers
  • depend on ActiveRecord internals across engines
  • introduce circular dependencies

Allowed Communication Patterns

Engines CAN communicate only via:

Public Services

ErpUsers::Services::CreateUser.call(...)

Public Interfaces

Defined contracts exposed by each engine.


Events (Future-ready design)

  • domain events
  • message-based communication (future evolution)

Creating a New Engine

Step 1 — Generate engine

rails plugin new engines/erp_new_engine --full --mountable

Step 2 — Register engine

Add to main application:

# config/application.rb

config.paths.add "engines/erp_new_engine/lib"

Step 3 — Define namespace

module ErpNewEngine
end

Step 4 — Mount engine

# config/routes.rb

mount ErpNewEngine::Engine, at: "/erp_new_engine"

Step 5 — Define engine boundaries

Each engine MUST clearly define:

  • purpose
  • domain responsibility
  • dependencies
  • public APIs
  • internal services
  • models (if needed)

Engine Testing Rules

Every engine MUST include:

  • unit tests
  • service tests
  • optional feature/system tests
bundle exec rspec engines/erp_users

Engine Structure Standard

engines/erp_users/
├── app/
│   ├── controllers/
│   ├── models/
│   ├── services/
│   └── views/
├── lib/
├── config/
├── spec/
└── erp_users.gemspec
└── README.md

Engine Isolation Rules

Engines MUST:

Allowed

  • call public services from other engines
  • use shared interfaces
  • use core engine primitives

Not allowed

  • direct model access across engines
  • internal service calls between engines
  • shared database logic without interface

Dependency Direction Rule

Engine dependencies MUST flow like this:

erp_core  all engines
erp_accounts  users/workers/inventory
erp_users  workers
erp_inventory  workers

Never reverse dependencies.


Core Engine Responsibility

erp_core

  • shared domain logic
  • base services
  • global helpers

BUT:

MUST remain minimal and stable


Ownership Model

Each engine has:

  • clear owner responsibility
  • isolated domain logic
  • independent test suite

Engine Review Checklist

Before approval:

  • [ ] Engine boundaries respected
  • [ ] No cross-engine internal coupling
  • [ ] Public services used correctly
  • [ ] Tests included
  • [ ] Multi-tenancy respected
  • [ ] No shared hidden logic introduced

Mental Model

Engine = Mini Product inside ERP Plus

Why this exists

Without this guide:

  • engines become coupled
  • architecture degrades
  • system becomes monolith spaghetti

With this guide:

  • ✔ scalable architecture
  • ✔ clear ownership
  • ✔ enterprise-grade modularity
  • ✔ safe external contributions

Final Definition

An engine is a fully isolated domain module that behaves like a mini-application inside a controlled monolith ecosystem.


Architecture:

Architecture Engine

Contracts:

Contracts Engine

Development Process:

Workflow

PR Standard