Toss Backend is the orchestration layer for the Trustless OSS platform. It connects GitHub activity with bounty state, contributor wallets, and escrow operations while keeping slow or retryable work in background jobs.
Once a bounty is labelled and assigned, it advances on its own: every step is
a BullMQ job that re-checks the live
rules, and transient failures retry with backoff. See
docs/jobs.md.
| Capability | What it handles |
|---|---|
| 🐙 GitHub integration | GitHub App installations, repository sync, signed webhooks, issues, assignments, labels, and pull requests |
| 🎯 Bounty lifecycle | Reward tiers, contributor assignment, milestone creation, automatic payout, and payout status |
| 🔐 Authentication | Supabase bearer-token verification with GitHub identity extraction |
| 💸 Escrow operations | Unsigned transaction creation, deployment, funding, refunds, closure, and submission through Trustless Work |
| ⚙️ Background processing | BullMQ queues for webhooks, the bounty state machine, and scheduled escrow sync — with per-issue deduplication, automatic retries, and queue statistics (docs) |
| 🩺 Operations | Toasty migrations, dependency-aware health checks, request tracing, and graceful shutdown |
flowchart LR
GH["🐙 GitHub App<br/>events & webhooks"] -->|HMAC verified| API["⚡ Axum API"]
UI["🖥️ Trustless OSS<br/>frontend"] -->|Supabase bearer token| API
API --> DB[("🐘 PostgreSQL<br/>repos, issues & assignments")]
API -->|enqueue only| REDIS[("🔴 Redis<br/>cache & BullMQ")]
REDIS --> WORKERS["⚙️ BullMQ workers<br/>github-webhook · advance-issue<br/>push-milestone · release-payout"]
WORKERS -->|re-check rules| DB
WORKERS --> GH
WORKERS --> TW["🤝 Trustless Work API"]
TW --> STELLAR["🌐 Stellar escrow"]
The common bounty journey is:
- A maintainer connects a repository and configures reward tiers.
- GitHub sends signed issue, assignment, label, and pull-request events. Routes verify the signature and enqueue; they never move funds themselves.
- A contributor connects a payout wallet, and the milestone is pushed to escrow.
- A merged PR or closed issue satisfies the release rule, and the payout goes out automatically.
- If a step is not ready yet — no wallet, issue still open — the flow parks and resumes by itself when the missing piece arrives. Nobody presses retry.
Every job re-reads Postgres, GitHub, and the escrow contract before acting, so an already-paid bounty is always a no-op. Full job documentation →
| Layer | Technology |
|---|---|
| API | Rust 2021, Axum 0.8, Tokio |
| Data | PostgreSQL 16, Toasty 0.10 ORM, Redis 7 |
| Authentication | Auth, GitHub identity |
| Integrations | GitHub App API, Trustless Work, Stellar |
| Observability | tracing, dependency-aware health checks |
| Local infrastructure | Docker Compose (PostgreSQL + Redis only) |
- Rust stable toolchain (MSRV for Toasty is ~1.95+)
- Docker with Docker Compose
- GitHub App, Supabase, Stellar, and Trustless Work credentials for the integration flows you want to exercise
cp .env.example .envOpen .env and replace the placeholder credentials. The application validates
its required configuration at startup, so all required values must be present.
Never commit the populated .env file.
Local defaults match Docker Compose:
| Service | URL |
|---|---|
| PostgreSQL | postgres://postgres:postgres@localhost:5435/trustless_oss |
| Redis | redis://localhost:6379 |
docker compose up -d
docker compose psThis starts PostgreSQL on localhost:5435 and Redis on localhost:6379.
On every server start (cargo run / deploy), the app applies pending SQL from
toasty/migrations (embedded into the binary). Already-applied migrations are skipped.
Generate new migration files after you change models under src/shared/models/schema/:
cargo run --bin migrate -- migration generate --name describe_your_changeThen restart the server (or run apply manually):
cargo run --bin migrate -- migration apply
# or just:
cargo runCommit the updated toasty/ folder so deploys include the new SQL.
cargo runcargo run starts the toss-backend server (default binary). It listens at
http://localhost:5000 by default.
curl http://localhost:5000/
curl http://localhost:5000/api/v1/healthThe root endpoint confirms that the API is running. The detailed health endpoint
also reports PostgreSQL, Redis, environment, and Trustless Work status. Browse
the full API (repos, contributor, bounty, escrow, GitHub webhooks, and health)
at http://localhost:5000/swagger.
Tip
If port 5000 is already in use, change PORT in .env and use the same
port in your health-check URL.
The complete template lives in .env.example.
| Group | Variables | Purpose |
|---|---|---|
| Runtime | NODE_ENV, PORT, LOG_LEVEL |
Server mode, address, and logging |
| Infrastructure | DATABASE_URL, REDIS_URL |
PostgreSQL, cache, and job queue |
| Background jobs | BULLMQ_PREFIX, BULLMQ_CONCURRENCY, ESCROW_SYNC_INTERVAL_SECS |
Optional BullMQ tuning (docs) |
| Authentication | SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY |
Bearer-token verification |
| GitHub | GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_WEBHOOK_SECRET |
App authentication and webhook verification |
| Stellar | STELLAR_NETWORK, platform and dispute-resolver keypairs |
Transaction signing and network selection |
| Trustless Work | TRUSTLESS_WORK_API_KEY, TRUSTLESS_WORK_BASE_URL |
Escrow API access |
| Application | APP_URL, WEBHOOK_URL |
Frontend and public webhook locations |
| Local webhook relay | DEV_WEBHOOK_PROXY_ENABLED, SMEE_SOURCE_URL, SMEE_TARGET_URL |
Optional development-only GitHub relay |
The migrate binary also accepts TOASTY_CONNECTION_URL as an override for
DATABASE_URL.
Protected application routes use Authorization: Bearer <supabase-access-token>.
GitHub webhooks instead require a valid X-Hub-Signature-256 signature.
Uploads use a direct-to-storage flow: POST /api/v1/upload with JSON fields
contentType, size, and optional folder returns a short-lived upload_url.
Then PUT the raw file bytes to that URL with the returned headers. Configure
the storage bucket's CORS policy to allow PUT from the frontend origin.
| Area | Main endpoints |
|---|---|
| System | GET /, GET /health, GET /api/v1/health, GET /api/v1/health/database, GET /api/v1/health/redis, GET /api/v1/health/trustless-work, GET /api/v1/queue/stats |
| Repositories | GET /api/v1/repos, POST /api/v1/repos/connect, POST /api/v1/repos/sync-installation, GET/DELETE /api/v1/repos/{repoId} |
| Issues and rewards | GET /api/v1/repos/{repoId}/issues, PUT /api/v1/repos/{repoId}/rewards, POST /api/v1/issues/{issueId}/retry (emergency override — not part of the happy path) |
| Contributors | POST /api/v1/wallet/connect, GET /api/v1/contributor/me |
| Milestones | POST /api/v1/milestones/push |
| Escrow | POST /api/v1/escrow/create-unsigned, /submit-deploy, /fund-unsigned, /submit-fund, /refund, /close-unsigned, /submit-close |
| GitHub | POST /api/v1/webhooks/github |
| Docs | GET /swagger (full OpenAPI UI), GET /api/v1-doc/openapi.json |
Interactive docs for every public endpoint live at /swagger. Request/response schemas and bearer-auth requirements are included in the spec.
Toss-Backend/
├── src/
│ ├── bin/migrate.rs # Toasty migration CLI
│ ├── modules/ # Repo, GitHub, bounty, contributor, and escrow domains
│ ├── shared/models/ # Entity DTOs + Toasty schema models
│ ├── infra/ # PostgreSQL (Toasty), Redis, BullMQ queue + jobs, cache, Stellar
│ ├── middleware/ # Authentication and request middleware
│ ├── routes/ # Health and operational routes
│ ├── lib.rs # Shared library crate
│ ├── config.rs # Environment configuration
│ ├── app.rs # Axum router assembly
│ └── main.rs # Server startup and graceful shutdown
├── docs/jobs.md # Queues, job names, retry policy, automation rules
├── tests/ # Integration tests (BullMQ against a real Redis)
├── toasty/ # Generated SQL migrations, snapshots, history
├── Toasty.toml # Toasty migration config
├── docker-compose.yml # Local PostgreSQL + Redis
└── .env.example # Safe configuration template
Run the same core checks used by the project before opening a pull request:
cargo fmt --check
cargo build
cargo testUseful local commands:
# API server (default binary)
cargo run
# Migrations
cargo run --bin migrate -- migration generate --name my_change
cargo run --bin migrate -- migration apply
# Follow infrastructure logs
docker compose logs -f postgres redis
# Stop local infrastructure
docker compose down
# Stop and remove local database/cache volumes
docker compose down -vWarning
docker compose down -v deletes the local PostgreSQL and Redis volumes.
migration reset drops all tables in the connected database. Use either only
when you intentionally want a clean local data reset.
Issues and pull requests are welcome. Before submitting a change:
- Keep changes focused on one concern.
- Add or update tests for changed behavior.
- Run the formatting, build, and test commands above.
- Explain any configuration or migration changes in the pull request.
- Commit updated files under
toasty/when you change schema models.
Have an idea or found a bug? Open an issue.
Built for open-source contributors by Trustless OSS.
