The off-chain backbone of the TrustFlow Protocol.
TrustFlow Core is the backend API service that powers off-chain logic for the TrustFlow gig-economy platform. Built with NestJS and TypeScript, it bridges the Stellar/Soroban blockchain with real-world application features β handling authentication, escrow state management, webhook delivery, and Prometheus-grade observability.
- π JWT Authentication with Wallet Signatures: Secure wallet-based auth using Stellar signature verification. Users authenticate by signing a cryptographic challenge with their Freighter wallet, proving ownership without exposing private keys.
- πΌ Escrow Management: Full CRUD API for escrow entities β creation, funding, milestone tracking.
- π Stellar Integration: Native Horizon and Soroban RPC helpers for on-chain reads and writes.
- π Webhook Engine: Event-driven webhook dispatch with automatic retry logic.
- π Monitoring & Metrics: Built-in Prometheus metrics, health checks, and alerting helpers.
- π‘οΈ Distributed Rate Limiting: Redis-backed per-IP and per-wallet token buckets with sliding-window abuse detection and temporary lockouts.
backend/
βββ src/
βββ admin/ # Read-only protocol analytics dashboard (admin-only)
βββ auth/ # Wallet-signature JWT auth β challenge/verify, nonce store, guard
βββ common/ # Cross-cutting: rate limiting, Redis client, idempotency, pagination, logging, DB, filters
βββ config/ # Zod-validated env config, .env loading
βββ deliverable/ # Gig deliverable submission and review
βββ dispute/ # Dispute resolution saga (juror voting, resolution)
βββ escrow/ # Escrow vault CRUD, milestone release, disputes
βββ escrow-reconciliation/ # Reconciles off-chain escrow state against on-chain Soroban state
βββ escrow-write/ # Builds unsigned Soroban release transactions for client signing
βββ event-ingestion/ # Polls Soroban RPC for contract events, feeds the outbox
βββ gig/ # Gig solicitation postings β accept/cancel, auto-expiry sweep
βββ ipfs-pinning/ # Multi-provider IPFS pinning (Pinata/Web3.Storage/Infura) with failover
βββ migration/ # Schema migration registry/runner (admin-triggered run/rollback)
βββ milestone-notifications/# WebSocket gateway for milestone/escrow event notifications
βββ monitoring/ # Health checks (`/health`) and Prometheus metrics (`/metrics`)
βββ notification/ # Shared notification dispatch types/service
βββ outbox/ # Transactional outbox relay to WebSocket/webhooks/workers
βββ reputation/ # Wallet reputation scoring with time decay
βββ sentry/ # Sentry error-monitoring integration
βββ soroban-event-indexer/ # Indexes raw Soroban events into Redis for `/events/soroban`
βββ stellar/ # Horizon/Soroban RPC clients, failover, network config
βββ testing/ # Shared test doubles (fake Redis client)
βββ user-profile/ # Wallet-linked user profiles β search, ratings, verification
βββ webhook/ # Webhook registration/dispatch, HMAC signing, Discord notifications
βββ main.ts # App entry point
- Node.js >= 20
- A Stellar RPC endpoint (testnet or mainnet)
- Freighter wallet (for client-side wallet signature testing)
npm installCopy the example env file into backend/ (where the app looks for it) and fill in your values:
cd backend
cp ../.env.example .envKey variables:
JWT_SECRET=your-secret
SOROBAN_RPC_URL=https://soroban-testnet.stellar.org
STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org
REDIS_URL=redis://localhost:6379
RATE_LIMIT_ABUSE_WINDOW_SECONDS=300
RATE_LIMIT_ABUSE_THRESHOLD=5
RATE_LIMIT_LOCKOUT_SECONDS=900
# allow (fail open, default) or deny (503 + Retry-After) when Redis is down; /auth/* always denies
RATE_LIMIT_ON_REDIS_ERROR=allow
REDIS_COMMAND_TIMEOUT_MS=1000See .env.example for the full list of variables, including optional IPFS, database, and admin settings.
What dependencies are required? See Runtime Dependencies for a detailed breakdown of each external service (Redis, PostgreSQL, Stellar, IPFS, etc.), what happens when they're unset or down, and which are mandatory for production.
# Development
cd backend
npm run dev
# Production
npm run build && npm start
# Run tests
npm test
# Run CI checks locally
./scripts/ci-check.shSee Backend Setup Instructions for detailed development workflow.
Swagger UI: http://localhost:3001/api/docs
OpenAPI JSON: http://localhost:3001/api/docs-json
(Disabled in production unless SWAGGER_ENABLED=true; protect with SWAGGER_USER/SWAGGER_PASSWORD.)
Full guide: API Documentation
docs/state-model.md β Reference for the Escrow, Gig, and DisputeSaga state machines: which transitions are driven by API calls, on-chain Soroban events, or background workers, plus a catalogue of known deviations from the intended model.
| Controller path | Auth required | Swagger tag |
|---|---|---|
/auth |
No (issues the JWT) | Authentication |
/escrows |
No (IP rate-limited only) | Escrow |
/webhooks |
No (IP rate-limited only) | Webhooks |
/health, /metrics |
No | Monitoring |
/gigs |
Partial β reads public, writes require JWT | Gigs |
/profiles |
Partial β reads public (never include the email address), writes and GET /profiles/me require JWT |
User Profiles |
/deliverables |
Yes (JWT) | Deliverables |
/dispute |
Yes (JWT) | Dispute Resolution |
/reputation |
No | Reputation |
/ipfs/pins |
Yes (JWT) | IPFS Pinning |
/outbox |
Yes (JWT) | Outbox |
/escrow-reconciliation |
Yes (JWT) | Escrow Reconciliation |
/event-ingestion |
No | Event Ingestion |
/events/soroban |
No | Soroban Events |
/stellar |
No | Stellar |
/rpc-status |
Yes (JWT) | RPC Status |
/migrations |
Yes (JWT + admin allow-list) | Schema Migrations |
/admin/analytics |
Yes (JWT + admin allow-list) | Admin |
GET /auth/challengeβ Get authentication challenge for wallet signingPOST /auth/verifyβ Verify wallet signature, returns JWT- JWT Guard protects downstream routes that require it (see table above β several routes are intentionally public and rely on IP-scoped rate limiting instead).
- Request Challenge: Client requests a cryptographic challenge for their wallet address
- Sign Challenge: User signs the challenge with their Freighter wallet
- Verify & Get Token: Client sends the signature to verify and receive a JWT token
- Use Token: Include JWT in Authorization header for authenticated requests
# 1. Get challenge
curl "http://localhost:3001/auth/challenge?address=GXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# 2. Sign challenge with Freighter wallet (client-side)
# 3. Verify signature and get JWT
curl -X POST http://localhost:3001/auth/verify \
-H "Content-Type: application/json" \
-d '{"address":"G...","signature":"..."}'
# 4. Use JWT for authenticated requests
curl http://localhost:3001/escrows \
-H "Authorization: Bearer <jwt-token>"POST /escrowsβ Create a new escrow vault.GET /escrows/:idβ Fetch escrow state and milestone details.GET /escrows/depositor/:addressβ Get all escrows by depositorPOST /escrows/:id/releaseβ Approve a milestone tranche.POST /escrows/:id/disputeβ Raise a dispute (triggers Discord notification).
POST /webhooksβ Register a webhook endpoint (supports optional HMACsecretfor payload signing).DELETE /webhooks/:idβ Unregister a webhook.- HMAC Signatures: Secure outgoing payloads with
X-TrustFlow-Signature(HMAC-SHA256). Verification Guide - Automatic retry logic handles delivery failures gracefully.
- Discord Integration: Automatically notifies a Discord channel when disputes need jurors. Setup Guide
GET /healthβ Liveness and readiness probe.GET /metricsβ Prometheus-compatible metrics endpoint.
- Wallet Signature Verification: Uses @stellar/stellar-sdk for cryptographic signature verification
- Challenge Expiration: Challenges expire after 60 seconds to prevent replay attacks
- One-Time Use: Each challenge can only be used once
- JWT Expiration: Tokens expire after 24 hours
- Address Validation: Validates Stellar public key format (G-prefixed, 56 characters)
- Input Validation: Uses class-validator DTOs on all endpoints
- Distributed Rate Limiting: Coordinates per-IP and per-wallet token buckets through Redis across API nodes
- Abuse Lockouts: Tracks repeated limit violations in a sliding window and temporarily locks abusive identities
- Guard Middleware: All protected routes require valid JWT via JwtAuthGuard
- Environment Secrets: Never logged or exposed in responses
For detailed authentication implementation documentation, see AUTH_IMPLEMENTATION.md.
The project uses GitHub Actions for continuous integration β a single ci job (lint,
format check, type check, tests against a redis:7-alpine service container, build, and an
npm audit gate) running on the Node version pinned in the repo-root .nvmrc:
- β Automated Testing: Runs on every PR affecting backend code
- β Code Quality: ESLint and Prettier checks
- β Type Safety: TypeScript compilation and type checking
- β
Dependency Audit:
npm audit --audit-level=highblocks the build on high/critical advisories - β
Branch Protection: PRs blocked on a failing
cicheck
See CI/CD Documentation for details.
Local CI Check:
cd backend && ./scripts/ci-check.sh- JWT Authentication with Wallet Signatures: Implemented Stellar signature verification
- GraphQL Layer: Optional GraphQL gateway over REST endpoints.
- Rate Limiting: Per-wallet and per-IP distributed throttling with Redis-backed abuse lockouts.
- Event Sourcing: Full audit log for all escrow state transitions.
- Multi-network Support: Seamless mainnet/testnet switching via config.
- Token Refresh: Implement refresh token mechanism for better UX
- Redis Integration: Distributed challenge (nonce) storage via
NonceStoreService, backed byREDIS_CLIENT
- Documentation: Full API Reference
- Issues: Report bugs or request features
- Discussions: Stellar Community Forum
Securing the future of work, one transaction at a time.
MIT License. Copyright (c) 2026 TrustFlow Protocol.