Thank you for your interest in contributing to Fluid — the multi-chain fee sponsorship platform for the Stellar network. This guide covers everything you need to go from a fresh clone to an approved pull request.
- Repository Layout
- Architecture Decisions
- Development Setup
- Branching Strategy
- Commit Convention
- Pull Request Process
- Code Review Expectations
- Environment Variables
- Code Style
- Testing
fluid/
├── fluid-server/ Rust signing engine — primary production backend (Axum + sqlx)
├── server/ Node.js parity server and admin API (Express + Prisma + BullMQ)
├── admin-dashboard/ Next.js 15 admin UI (React 19, Tailwind 4)
├── client/ TypeScript client library (browser + Node.js)
├── fluid-cli/ Rust CLI tool
├── fluid-py/ Python SDK (Maturin/PyO3 bindings)
├── fluid-go/ Go client library
├── proto/ Protocol Buffer definitions (gRPC contract)
└── docs/ Documentation and Architecture Decision Records
└── adr/ ADR index and individual records
This is an Nx monorepo. Each sub-package is independently buildable and testable.
Major architectural choices are recorded as Architecture Decision Records in docs/adr/. Before proposing a significant change to the tech stack, internal protocols, or cross-package APIs:
- Check whether an existing ADR covers the area.
- If the decision is new or changes an existing record, open a discussion or draft a new ADR alongside your pull request using the template.
Key ADRs to read before contributing:
| ADR | Topic |
|---|---|
| 001 | Chain-agnostic fee-sponsor interface |
| 002 | Rust signing engine rationale |
| 003 | gRPC bridge between Node.js and Rust |
| 004 | Prisma ORM selection |
| Tool | Version |
|---|---|
| Rust toolchain | stable (via rustup) |
| Node.js | 18+ |
| pnpm | 9+ |
| Docker & Docker Compose | any recent version |
# 1. Clone the repository
git clone https://github.com/Stellar-Fluid/fluid.git
cd fluid
# 2. Copy environment variables
cp .env.example .env
# Fill in the required values — see .env.example comments
# 3. Install JavaScript dependencies
pnpm install
# 4. Build the Rust engine
cd fluid-server && cargo build && cd ..
# 5. Start the full local stack (Stellar Quickstart, PostgreSQL, Redis)
docker compose up
# 6. Run database migrations (Node API / Prisma)
cd server && npx prisma migrate dev| Service | URL |
|---|---|
| Rust engine | http://localhost:3000 |
| Node API | http://localhost:3001 |
| Admin dashboard | http://localhost:3002 |
| PostgreSQL | localhost:5432 |
| Redis | localhost:6379 |
| Stellar Horizon (local) | http://localhost:8000 |
| Branch | Purpose |
|---|---|
main |
Always deployable. Protected — no direct pushes. |
feature/<issue>-<short-description> |
New feature or enhancement. |
fix/<issue>-<short-description> |
Bug fix. |
docs/<issue>-<short-description> |
Documentation only. |
chore/<short-description> |
Tooling, CI, dependencies. |
Rules:
- Always create your branch from
main(git checkout -b feature/123-my-feature origin/main). - Keep branches short-lived — open a PR as soon as you have a reviewable diff, even if it's a draft.
- One logical change per branch. Avoid mixing features with unrelated refactors.
- Delete your branch after it is merged.
This project enforces Conventional Commits via commitlint — both locally (git hook) and in CI on every pull request.
<type>(<optional scope>): <short description>
[optional body]
[optional footer(s)]
| Type | When to use |
|---|---|
feat |
A new feature visible to users or API consumers |
fix |
A bug fix |
perf |
Performance improvement |
docs |
Documentation only |
style |
Formatting, whitespace — no logic change |
refactor |
Code change that neither fixes a bug nor adds a feature |
test |
Adding or correcting tests |
chore |
Build process, dependency updates, tooling |
ci |
CI/CD configuration |
revert |
Reverts a previous commit |
feat(client): add Web Worker signing for offthread performance
fix(server): handle missing Horizon URL in fee-bump handler
perf(fluid-server): parallelise XDR serialisation in signing pool
docs: comprehensive contributing guide and pr template
chore(deps): bump stellar-sdk to 14.6.1
Use the package name as scope when the change is isolated to one sub-package (client, server, fluid-server, admin-dashboard, fluid-cli, fluid-py, fluid-go). Omit scope for cross-cutting changes.
commitlint runs automatically via the commit-msg git hook (installed by the setup above). If a commit is rejected, amend or reset and re-word your message.
- Open early. Draft PRs are welcome — they invite early feedback and prevent wasted effort.
- Reference the issue. Include
closes #NNNorrelates to #NNNin the PR description. - Fill in the PR template. The
.github/PULL_REQUEST_TEMPLATE.mdchecklist must be completed before requesting review. - Keep PRs focused. One feature or fix per PR. Large changes are harder to review and slower to merge.
- All new environment variables must have a matching entry in
.env.examplewith an explanatory comment. - Update ADRs in
docs/adr/for any significant architectural decision. - Provide evidence. Every PR that changes runtime behaviour must include a screenshot, log snippet, or test output proving it works. PRs without evidence will not be approved.
- Ensure CI passes. Address all lint, type, and test failures before requesting review.
- Respond to review comments within two business days.
- Prefer addressing feedback with new commits during review; squash only at merge time.
- Explain non-obvious decisions in PR comments rather than inline code comments.
- Be constructive and specific. "This is wrong" is not actionable; "this will panic on empty input because…" is.
- Distinguish blocking issues (
must fix) from suggestions (nit:orconsider:). - Approve only when you would be comfortable being on-call for the change.
- Target a first review within two business days of PR creation.
- Squash and merge for feature and fix branches (keeps
mainhistory linear). - Merge commit for release branches or when preserving intermediate commits matters.
- At least one approving review from a maintainer is required.
- All CI checks must be green.
Copy .env.example to .env and fill in the values documented there. Never commit secrets.
Rules for PRs that introduce new environment variables:
- Add an entry to
.env.exampleimmediately above or within the relevant section. - Include a comment explaining the variable's purpose, accepted values, and default.
- Mark required variables clearly; use a safe default for optional ones.
cargo fmt # format
cargo clippy --all-targets -- -D warnings # lint; warnings are errors in CIpnpm exec nx lint <project> # ESLint via NxFollow the ESLint configuration in each sub-package. Key conventions:
- No
anyunless unavoidable and commented with justification. - Prefer
constoverlet; avoidvar. - Comments only when the why is non-obvious — never describe what the code does.
ruff check .go fmt ./...
go vet ./...# Rust engine
cd fluid-server && cargo test
# Node API
cd server && npm test
# Client library
cd client && npm test
# Admin dashboard (unit + e2e)
cd admin-dashboard && npm test
cd admin-dashboard && npx playwright test
# Node ↔ Rust parity check
cd server && npm run parity:rust| Change type | Required coverage |
|---|---|
| New handler / endpoint | Handler unit test + integration test |
| New service | Service unit test |
| Bug fix | Regression test that would have caught the bug |
| Performance change | Benchmark output showing improvement |
| Docs / CI | No test required |
Evidence that your change works (log output, screenshot, benchmark result) must be included in the PR description. Issues will not be closed without it.