This is the single authoritative guide for setting up Scavenger locally. If you find setup instructions elsewhere in the repo, treat them as outdated pointers to this file.
- Last reviewed: see git history
- Scope: local development only. Deployment is covered in DEPLOYMENT_RUNBOOK.md.
- Prerequisites
- Clone and install
- Environment variables
- Running the stack
- Verifying your setup
- Per-service commands
- Docker reference
- Troubleshooting
| Tool | Version | Why |
|---|---|---|
| Node.js | 18+ | frontend, indexer, tooling |
| pnpm or npm | latest | package manager (see repo root packageManager) |
| Rust | stable (see rust-toolchain.toml) |
smart contracts, backend |
| Docker + Compose | latest | local Postgres, Redis, Stellar standalone |
Stellar CLI (soroban) |
latest | deploy contract, invoke functions |
| Git | any recent | obviously |
Install per your OS. Verify with:
node --version
pnpm --version # or: npm --version
rustc --version
docker --version
soroban --versionThe Rust toolchain is pinned to stable in rust-toolchain.toml. rustup
picks it up automatically inside the repo.
git clone <repo-url> scavenger
cd scavengerInstall dependencies in each workspace you will run:
cd frontend && npm install && cd ..
cd indexer && npm install && cd ..Rust crates are fetched on the first cargo build or cargo test.
Copy each example file and fill in the values you need. Each file's comments say which variables are required for local development.
| File | Used by |
|---|---|
.env.example (root) |
backend and Docker Compose |
frontend/.env.example |
frontend (Vite, VITE_* variables) |
indexer/.env.example |
indexer |
cp .env.example .env
cp frontend/.env.example frontend/.env
cp indexer/.env.example indexer/.envFor local development the Firebase variables are the only ones that need real
values. The Stellar variables are pre-configured for the local standalone
network. Once you deploy the contract, set the returned ID as CONTRACT_ID in
.env and indexer/.env, and as VITE_CONTRACT_ID in frontend/.env, then
restart the services.
docker compose up -d
docker compose ps # wait for (healthy) on every serviceCompose starts these services:
| Service | Port | Purpose |
|---|---|---|
stellar |
8000 | Standalone Stellar network (Horizon + Soroban RPC) |
postgres |
5432 | Indexer database (scavngr; scripts/seed.sql creates the sync_status table on first start) |
redis |
6379 | Cache |
backend |
8080 | REST API |
indexer |
3001 | Event indexer |
frontend |
5173 | Web app |
Stellar needs about 30 seconds to initialise. The indexer and frontend wait on
health checks, so do not start them before stellar is healthy.
Start only the infrastructure, then run each workspace from the terminal:
docker compose up -d postgres redis stellarThen follow Per-service commands.
Run this once the stack is up:
# Generate a keypair and fund it from the local friendbot
soroban keys generate local-deployer --network standalone
curl "http://localhost:8000/friendbot?addr=$(soroban keys address local-deployer)"
# Build and deploy
cargo build --target wasm32-unknown-unknown --release
soroban contract deploy \
--wasm target/wasm32-unknown-unknown/release/stellar_scavngr_contract.optimized.wasm \
--source local-deployer \
--network standalone
# Set the returned contract ID in .env, then restart the services that use it
echo "CONTRACT_ID=<returned-id>" >> .env
docker compose up -d --force-recreate indexer frontendRecord the returned contract ID and set it as described in Environment variables.
docker compose ps # all services healthy
curl -sf http://localhost:8080/health # backend respondsThe compose file defines health checks for stellar, postgres, redis and
backend. The indexer has none, so check its logs instead:
docker compose logs -f indexer. Then open http://localhost:5173.
cd stellar-contract
cargo test --lib # unit tests
cargo test --test '*' # integration testscd backend
cargo run --bin scavenger-backend
cargo testcd indexer
npm run migrate # apply database migrations (needs a built dist/)
npm run dev # ts-node, watches src/
npm run test:unitcd frontend
npm run dev # Vite dev server on port 5173
npm test # vitest
npm run lint| File | Purpose |
|---|---|
docker-compose.yml |
Core development environment |
docker-compose.monitoring.yml |
Prometheus and Grafana |
docker-compose.logging.yml |
Loki and Promtail log aggregation |
Combine files with -f:
docker compose -f docker-compose.yml -f docker-compose.monitoring.yml up -dfrontend/Dockerfile,backend/Dockerfile,indexer/Dockerfile
To force a full rebuild of one service:
docker compose build --no-cache <service>
docker compose up -d <service>- Frontend: Vite HMR. Edits under
frontend/src/update the browser. - Backend:
cargo-watchrestarts on changes underbackend/src/. - Indexer:
npm run devwatchesindexer/src/.
docker compose stop # stop, keep volumes
docker compose down -v # stop and destroy volumes (fresh start)
docker compose exec backend cargo test
docker compose exec indexer npm test
docker compose exec postgres psql -U scavngr scavngr
docker compose exec redis redis-cli FLUSHALLStellar container takes too long to start. It needs about 30 seconds.
Wait for docker compose ps to show (healthy).
CONTRACT_ID is empty. The frontend and indexer start, but contract calls
fail. Deploy the contract and restart those services.
Port already in use. Stop any native PostgreSQL or Redis
(sudo systemctl stop postgresql redis-server), or override the host port in
a docker-compose.override.yml:
services:
frontend:
ports:
- "5174:5173"Port 8000 must be free for the standalone Stellar network.
Freighter wallet with the local network. In Freighter settings, add a custom network with:
- Horizon URL:
http://localhost:8000 - Soroban RPC URL:
http://localhost:8000/soroban/rpc - Passphrase:
Standalone Network ; February 2017