Thank you for your interest in contributing to RERP (Rust Enterprise Resource Planning)! 🎉
This guide will help you get started with contributing to the project. It is also the canonical contract for RERP's suite and microservice layout. New code, generation, migration, build, and deployment tooling must preserve these boundaries.
- Rust toolchain (stable) - Install Rust
- Python 3.12+ (for generation scripts)
- Git for version control
- BRRTRouter - BRRTRouter repository (for code generation)
-
Fork and clone the repository:
git clone https://github.com/microscaler/rerp.git cd rerp -
Explore the project structure:
# View suite-nested service specifications find openapi -mindepth 3 -maxdepth 3 -name openapi.yaml # View generated/implementation crate pairs find microservices -mindepth 3 -maxdepth 3 -type d \ \( -name gen -o -name impl \)
-
Generate system BFF specs (optional, for testing): run
just initthenrerp bff generate-system. -
Pre-commit hooks (recommended): run
just initthenjust install-hooks. Before each commit this runs:- Tooling QA:
just qa(lint, format-check, tooling tests) - microservices-fmt: if
microservices/changed vs HEAD, runsjust fmt-rustfor the suite-nested Rust workspace; fast if Tilt has recently built.
- Tooling QA:
git checkout -b feature/your-feature-name- Follow Rust best practices and conventions
- Ensure code compiles without warnings
- Add tests for new functionality
- Update documentation as needed
cd microservices
# Build all crates
cargo build --workspace
# Run tests
cargo test --workspace
# Format code
cargo fmt
# Check linting
cargo clippy --workspaceCommit messages must follow the Conventional Commits specification. This is enforced in CI via commitlint; PRs with invalid commit messages will fail.
Format: <type>[optional scope]: <description> (subject line max 1500 characters; extra space for agentic tracking)
Examples:
feat: add new service endpointfeat(auth): add login endpointfix: correct validation logicdocs: update API documentationtest: add tests for inventory servicechore(deps): bump crate-x to 1.2
Common types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert.
To validate before pushing: npx commitlint --from HEAD~1 (requires Node; or rely on CI).
- Push your branch to your fork
- Create a pull request with a clear description
- Reference any related issues
- Ensure CI checks pass
We welcome contributions in the following areas:
- Enhance service specs: Add complete schemas, examples, and detailed descriptions
- Add missing endpoints: Identify and document additional API endpoints
- Improve documentation: Enhance service descriptions and parameter documentation
- Implement business logic: Add handlers and controllers for services
- Add validation: Implement request/response validation
- Error handling: Improve error handling and user feedback
- Unit tests: Add tests for individual services and functions
- Integration tests: Test service interactions and workflows
- Load testing: Performance and scalability testing
- User guides: Create guides for using RERP services
- API documentation: Improve OpenAPI specifications
- Code examples: Add practical usage examples
- Planning documents: Design proposals, PRDs, and analysis documents (see "Planning Documents" section below)
- Current authority: Start at
docs/README.md; do not infer authority from filenames, timestamps, or LLM wiki summaries - Lifecycle and supersession: Follow
docs/DOCUMENTATION_GOVERNANCE.md - Architecture decisions: Allocate and register ADRs through
docs/adrs/README.md
- Enhance automation: Improve GitHub Actions workflows
- Add checks: Additional quality checks and validations
- Deployment: Improve deployment processes
./docs/ or its subdirectories.
Placement does not make a document authoritative. New documents must use the
controlled lifecycle and metadata in
docs/DOCUMENTATION_GOVERNANCE.md.
Accepted decisions live in ADRs; approved requirements remain in PRDs or modes
of operation; analyses and completion reports remain dated evidence. Replaced
documents are explicitly marked and linked to their successor rather than
silently deleted.
docs/ai/- AI-generated planning, analysis, and implementation status documentsdocs/adrs/- Architecture Decision Records (ADRs)docs/(root) - Design proposals, PRDs, and other planning documents
- Design proposals:
docs/DESIGN_PROPOSAL_*.md - PRDs:
docs/*_PRD.md - Analysis documents:
docs/*_ANALYSIS.md - Status documents:
docs/*_STATUS.mdordocs/*_COMPLETE.md - Implementation status:
docs/ai/*_COMPLETE.mdordocs/ai/*_STATUS.md
✅ Correct locations:
docs/DESIGN_PROPOSAL_RELEASE_CI_INTEGRATION.mddocs/VERSIONING_STRATEGY_ANALYSIS.mddocs/ACCOUNTING_SUITE_ENRICHMENT_PRD.mddocs/ai/OPENAPI_ENRICHMENT_ANALYSIS.md
❌ Incorrect locations (NOT ALLOWED):
DESIGN_PROPOSAL_*.md(project root)VERSIONING_STRATEGY_*.md(project root)ANALYSIS_*.md(project root)
- Keeps project root clean and organized
- Makes documentation easy to find
- Follows standard documentation structure
- Prevents accidental commits of planning documents in wrong locations
If you find planning documents in the project root, move them to ./docs/ immediately.
- Follow Rust API Guidelines
- Use
cargo fmtfor formatting - Run
cargo clippyand fix warnings - Write comprehensive doc comments
- Maintain test coverage (target: 65% minimum, 80% preferred)
- Use OpenAPI 3.1.0 format
- Include complete path definitions
- Define request/response schemas
- Add operation summaries and descriptions
- Follow RESTful conventions
- Use Conventional Commits (enforced in CI)
- Keep commits focused and atomic
- Rebase on main before submitting PRs
- Write clear PR descriptions
RERP is a multi-suite platform. Hauliage is useful prior art for the anatomy of one microservice, but Hauliage is a single product suite and therefore has a flat service tree. RERP adds a mandatory suite level to every contract, runtime, database, test, and deployment path.
The hierarchy is:
RERP platform
└── suite
├── suite-owned shared assets
└── microservice
├── generated API contract
└── user-owned implementation
For an Accounting invoice service:
openapi/accounting/invoice/openapi.yaml
microservices/accounting/
├── README.md
├── core/
├── entities/
├── migrations/
├── sql/
├── scripts/
├── tests/
└── invoice/
├── README.md
├── gen/
└── impl/
The same shape applies to every suite:
openapi/<suite>/<service>/openapi.yaml
microservices/<suite>/<service>/gen/
microservices/<suite>/<service>/impl/
deployment-configuration/profiles/<environment>/rerp/<suite>/
Do not flatten a RERP service to microservices/<service>. Do not put
suite-specific entities/, migrations/, sql/, scripts/, tests/, or
core/ directories at the repository root. Root-level assets are reserved for
capabilities that genuinely apply to every installed suite.
Each suite owns its complete optional installation boundary:
| Path | Responsibility |
|---|---|
microservices/<suite>/README.md |
Suite purpose, service inventory, runtime and verification guidance |
microservices/<suite>/core/ |
Pure shared domain calculations and invariants; no transport or database executor abstraction |
microservices/<suite>/entities/ |
Genuinely suite-wide foundation persistence models only |
microservices/<suite>/migrations/ |
Generated and authored migrations for that suite, plus suite-local application order |
microservices/<suite>/sql/ |
Suite-owned database contracts that are not entity-generated |
microservices/<suite>/scripts/ |
Suite-specific development and operational wrappers |
microservices/<suite>/tests/ |
Cross-service acceptance and suite installation-isolation tests |
deployment-configuration/profiles/<environment>/rerp/<suite>/ |
Suite-owned non-secret properties and SOPS-encrypted runtime credentials |
The presence of all suites in one Cargo workspace is a development convenience; it is not permission to install every suite. Build, Helm/Tilt selection, and migration application must all select the intended suites explicitly.
Environment profiles preserve the same installation boundary. Product and
suite configuration belongs in RERP, not in
shared-gitops-k8s-cluster/deployment-configuration/. Following the SAM Flux
pattern, the platform repository composes a Flux GitRepository and
Kustomization which source and reconcile the product-owned path. Tilt must
not apply the same resources or render/apply Helm workloads. The RERP Tiltfile
is an image-development loop: it may generate/build code and publish ordered
dev images, while Flux owns bootstrap Jobs, Helm releases, rollout, and drift
correction. The platform repository also owns the other side
of shared infrastructure contracts—for example, Pgpool's custom-user source
must carry the same rotated database credential as the owning RERP suite
profile. Never commit plaintext secrets or duplicate environment-specific
values in Helm defaults.
Every HTTP microservice has an OpenAPI contract, a generated crate, and a real implementation crate:
openapi/<suite>/<service>/
└── openapi.yaml # authoritative HTTP contract
microservices/<suite>/<service>/
├── README.md # human-owned service documentation
├── gen/ # disposable BRRTRouter output
│ ├── Cargo.toml
│ ├── config/
│ ├── doc/ # generated OpenAPI/API documentation
│ ├── static_site/
│ └── src/
│ ├── controllers/
│ ├── handlers/
│ ├── registry.rs
│ └── lib.rs
└── impl/ # deployable, user-owned service
├── Cargo.toml
├── build.rs # Lifeguard entity-registry generation
├── config/
├── seeds/
├── src/
│ ├── controllers/ # HTTP adapters only
│ ├── services/ # use cases and application orchestration
│ ├── models/ # service-owned Lifeguard persistence models
│ ├── validators/ # domain/request validation
│ ├── impl_registry.rs # real-handler registration/overrides
│ ├── lib.rs # reusable implementation surface
│ └── main.rs # executable composition and startup
└── tests/
├── bdd/
├── features/
├── integration/
└── openapi_parity.rs
Directories are added when the service needs them; empty scaffolding is not required. Their ownership does not change:
controllers/translate the generated transport contract to application calls and map results to responses. They do not own large business workflows.services/own application use cases and orchestration within that service.models/own that service's persistence entities and database views.validators/enforce rules not completely expressible in OpenAPI or database constraints.seeds/contain service-owned development/reference data, not schema DDL.tests/prove the real implementation rather than generated example handlers.config/contains runtime configuration packaged for that service.build.rsexposes the Lifeguard entity registry consumed by the top-level migrator.impl_registry.rsensures implemented controllers replace generated examples/stubs.
gen/ is disposable. Never fix business behavior, generated documentation, or
generated request/response types by editing it directly. Change the OpenAPI
source or BRRTRouter generator and regenerate.
Every database table or view has exactly one LifeModel owner and exactly one
migration source.
Use the following decision order:
- If a model belongs to one service, place it in that service's
impl/src/models/. - If several services use the concept but one service is its natural owner,
keep the model with the owner and reuse the owner's library/API rather than
copying the
LifeModel. - Only a concept that is genuinely foundational to the whole suite and has no
natural service owner belongs in
microservices/<suite>/entities/. - Never mirror a service model in the suite entity crate, and never define the same table in multiple service implementations.
The top-level migrator must reject duplicate table ownership. Similar Rust filenames are not the deciding factor; the effective schema/table identity is.
microservices/<suite>/core/ is not an entity repository and not another
service implementation. It contains pure reusable domain policy only.
openapi/<suite>/<service>/openapi.yamlis the public API source of truth.<service>/gen/doc/and<service>/gen/static_site/are generated artifacts.<service>/README.mddocuments human-owned service purpose, boundaries, dependencies, configuration, operations, and verification.<suite>/README.mddocuments suite-wide installation and service ownership.- Architecture decisions, PRDs, discoveries, and plans belong under
docs/.
Do not place human-authored architecture or operating knowledge under gen/;
it will be overwritten.
- Unit tests live beside the code they exercise or in the service
impl/tests/. - Service integration, BDD, feature, and OpenAPI-parity tests live under the
service
impl/tests/. - Cross-service workflows and suite installation-isolation tests live under
microservices/<suite>/tests/. - Seeds live under the owning service's
impl/seeds/and use the filename and idempotency rules enforced by Lifeguard migration tooling. - Schema changes are not seeds, and generated schema migrations are not test fixtures.
A suite BFF is still a service and keeps its own generated and implementation crates:
openapi/<suite>/openapi_bff.yaml
microservices/<suite>/bff/gen/
microservices/<suite>/bff/impl/
Its OpenAPI document is aggregated from the suite configuration, but real
composition and orchestration belong in bff/impl/.
A worker or scheduled processor that has no HTTP surface does not need an empty
gen/ crate. It remains owned by its suite and has its own package, source,
configuration, and tests, for example:
microservices/<suite>/workers/<worker>/
├── Cargo.toml
├── config/
├── src/
└── tests/
RERP has one top-level migration tool at microservices/migrator/, adapted from
Hauliage's proven service-registry pattern. RERP's additional requirement is
strict suite qualification.
The migrator consumes providers identified by (suite, service) and entity
registries exported by service impl crates or the suite foundation entity
crate. It must:
- Require explicit suite selection; no implicit "install everything" default.
- Generate, validate, plan, and apply only the selected suite.
- Write only beneath
microservices/<suite>/migrations/. - Produce suite-local
apply_order.txtand seed ordering. - Preserve service subdirectories within the suite migration set.
- Fail when two providers claim the same effective table/view.
- Fail on entity generation errors rather than silently omitting a provider.
- Prevent migration paths or order entries from crossing suite boundaries.
- Avoid cross-suite database foreign keys unless an accepted ADR explicitly makes one suite a required dependency of the other.
Example migration products:
microservices/accounting/migrations/
├── apply_order.txt
├── foundation/
├── general-ledger/
├── invoice/
└── accounts-receivable/
microservices/documents/migrations/
├── apply_order.txt
├── core/
└── render/
The migrator may depend on service implementation libraries because their
build.rs registries are the Hauliage pattern. Those dependencies must be
grouped or feature-gated by suite so an Accounting-only migration build does
not require Documents, HR, or any other optional suite.
Never create a repository-root migrations/ directory. Never make each service
container race to apply migrations independently; migration application is an
installation/suite operation.
Before opening a PR for a service change:
- Identify the owning suite and service.
- Update
openapi/<suite>/<service>/openapi.yamlwhen the HTTP contract changes. - Regenerate
gen/; do not hand-edit it. - Implement behavior in the service
impl/using the ownership rules above. - Verify every persistence table has one owner and migration provider.
- Add service tests, plus suite tests when behavior crosses service boundaries.
- Generate and validate migrations for the owning suite only.
- Update the service and suite README when ownership or operations change.
- Ensure Tilt/Helm/Docker descriptors use the full
(suite, service)identity.
rerp/
├── microservices/
│ ├── Cargo.toml # shared workspace and lockfile
│ ├── migrator/ # single suite-aware migration tool
│ └── <suite>/
│ ├── core/
│ ├── entities/
│ ├── migrations/
│ ├── sql/
│ ├── scripts/
│ ├── tests/
│ └── <service>/{gen,impl}/
├── openapi/
│ └── <suite>/
│ ├── bff-suite-config.yaml
│ ├── openapi_bff.yaml
│ └── <service>/openapi.yaml
├── tooling/ # suite-aware RERP CLI and build tooling
├── helm/ # generic chart plus suite/service values
├── docker/ # parameterized runtime image definitions
├── deployment-configuration/
│ └── profiles/<env>/rerp/<suite>/ # product config + SOPS credentials
├── docs/
│ ├── ai/
│ ├── adrs/
│ └── *.md
└── .github/
./docs/ or subdirectories.
The complete ownership rules—not just the abbreviated tree—are normative for new services and structural corrections.
Run Rust workspace commands from microservices/:
- ✅ All tests pass:
cd microservices && cargo test --workspace - ✅ Code compiles:
cd microservices && cargo build --workspace - ✅ No warnings:
cd microservices && cargo clippy --workspace -- -D warnings - ✅ Formatted:
cd microservices && cargo fmt --check - ✅ Documentation builds:
cd microservices && cargo doc --workspace
- Minimum coverage: 65%
- Target coverage: 80%
- Critical paths: 100%
- Issues: GitHub Issues
- Discussions: GitHub Discussions
We are committed to providing a welcoming and inclusive environment. Please be respectful and constructive in all interactions.
Thank you for contributing to RERP! 🚀