This document describes each external dependency the TrustFlow backend can use, what behavior changes when each is configured or unavailable, and which are required for production deployments.
| Dependency | Required for Production | Behavior When Unset | Behavior When Down |
|---|---|---|---|
| Redis | Yes | Per-instance state divergence | Rate limiting and caching degrade; some services fail |
| PostgreSQL | No (currently) | Not configured | Domain services log warnings |
| Stellar Horizon RPC | Yes (for on-chain reads) | Soroban events won't sync | Event ingestion stalls; status unhealthy |
| Soroban RPC | Yes (for on-chain operations) | On-chain operations fail at API boundary | Event ingestion stalls; status unhealthy |
| JWT_SECRET | Yes | Validation fails at startup | App won't start |
| ADMIN_ADDRESSES | No (defaults to deny-all) | Every admin route returns 403 | Admin routes return 403 |
| DISCORD_WEBHOOK_URL | No | Dispute notifications not sent | Dispute notifications silently dropped |
| IPFS Providers | No | Simulated in-memory pinning | No external pins; local tracking only |
| Sentry DSN | No | Errors logged locally only | Errors logged locally only |
Environment Variables:
REDIS_URL(connection string, e.g.,redis://localhost:6379)
What Uses It:
RateLimitGuard— per-IP and per-wallet request throttlingNonceStoreService— challenge/response anti-replay storeIdempotencyKeyService— deduplication for concurrent requestsDistributedLockService— coordinating sweep workers across instancesGigService— gig posting and acceptance storeOutboxService— event relay queueDeliverableService— deliverable submission trackingSorobanEventIndexerService— processed-event cursorEscrowService— escrow state (in production only)
Behavior When Unset:
- RateLimitGuard: Allows every request; logs a warning per request; no abuse protection
- NonceStoreService: Falls back to per-process in-memory maps; a challenge issued by one backend instance cannot be verified by another (security issue in clustered deployments)
- IdempotencyKeyService: Every request is considered unique; no deduplication
- DistributedLockService: Every instance believes it holds the lock; sweep workers run concurrently on all nodes (resource waste, potential duplication)
- GigService: Falls back to in-memory maps; gig state is lost on restart and not shared across instances
- OutboxService: Falls back to in-memory queue in non-production; throws startup error in production
- EscrowService: Falls back to in-memory maps in non-production; throws startup error in production (money-adjacent state must not diverge per-instance)
- Other services: Use in-memory fallbacks where Redis is absent
Behavior When Down (Connection Error):
- RateLimitGuard: Redis errors surface as HTTP 500 responses
- Most services: Operations fail or return 500; some log errors and continue with degraded behavior
- Health check (
GET /health): Redis health status reported as unhealthy
Production Requirement:
- REQUIRED. Redis is mandatory for rate limiting, coordinating distributed sweeps, and ensuring escrow state consistency across instances. A single-instance deployment still requires Redis; without it, there is no anti-abuse protection and escrow state is not durable.
Environment Variables:
DATABASE_URL(connection string, e.g.,postgresql://user:pass@localhost:5432/trustflow), ORDB_HOST,DB_PORT,DB_NAME,DB_USER,DB_PASSWORD(individual fields)DB_SSL,DB_SSL_CA,DB_SSL_CERT,DB_SSL_KEY,DB_SSL_REJECT_UNAUTHORIZED(SSL options)DB_POOL_MAX,DB_POOL_IDLE_TIMEOUT_MS,DB_POOL_CONNECTION_TIMEOUT_MS(pool tuning)
What Uses It:
- Currently not used by domain services. The
DatabaseServiceis initialized but domain code does not read from it.
Behavior When Unset:
DatabaseServicereports "not configured"HealthService.checkDatabase()reports healthy (because there is no database to check)- No impact on running application
Behavior When Down:
- No impact (database is not currently used)
Production Requirement:
- OPTIONAL (not yet used). This is infrastructure for future domain service adoption. See
PERSISTENT_STORAGE_SPIKE.mdfor the decision to defer relational storage to a later phase.
Environment Variables:
STELLAR_HORIZON_URL(defaults tohttps://horizon-testnet.stellar.org)STELLAR_HORIZON_ENDPOINTS(comma-separated failover URLs, optional)
What Uses It:
StellarService— fetching account info, transaction status, and chain-verified state- Event ingestion — reading historical ledger events (via Soroban RPC fallback when available)
Behavior When Unset:
- Defaults to testnet public endpoint; no credential-based failover
- Requests fall through to the default URL
Behavior When Down:
- Event ingestion stalls (cannot fetch ledger state or confirm transaction finality)
- Status endpoint shows Stellar health as unhealthy
- Client operations that depend on chain state fail with clear errors
Production Requirement:
- REQUIRED for on-chain operations. A deployed contract must be able to read state from Stellar; without it, escrow state cannot be verified or updated.
Environment Variables:
SOROBAN_RPC_URL(defaults tohttps://soroban-testnet.stellar.org)SOROBAN_RPC_ENDPOINTS(comma-separated failover URLs, optional)SOROBAN_START_LEDGER(contract deployment ledger; optional, defaults to current)TRUSTFLOW_CONTRACT_ID(contract address; required for on-chain operations)
What Uses It:
SorobanEventIndexerService— polling for contract eventsEventIngestionService— fetching events from specific ledgers and handling reorgsEscrowReconciliationService— reading escrow state directly from the contract- Escrow release transaction building — simulating contract calls to verify they will succeed
Behavior When Unset:
SOROBAN_RPC_URLdefaults to testnet; if unset and no failover is configured, falls back to defaultTRUSTFLOW_CONTRACT_IDis optional; operations that need it fail with a clear error- Event ingestion does not run (no contract to poll)
Behavior When Down:
- Event ingestion stalls (cannot poll for new events)
- Escrow reconciliation fails (cannot read contract state)
- Escrow release and other on-chain operations fail
- Status endpoint shows Soroban health as unhealthy
Production Requirement:
- REQUIRED. Without a working Soroban RPC endpoint, the backend cannot sync with the contract or dispatch transactions.
Environment Variables:
JWT_SECRET(required in production; optional with a test-default in development)
What Uses It:
AuthService— signing and verifying JWT tokens for wallet-based authenticationJwtStrategy— Passport middleware validating request tokens
Behavior When Unset:
- In
NODE_ENV=production: Validation fails at startup; app will not boot - In
NODE_ENV=developmentorNODE_ENV=test: Falls back toTEST_ONLY_JWT_SECRET(clearly marked for testing only)
Behavior When Down:
- No external service; validation is cryptographic only
- Tokens signed with a changed secret are immediately invalid
Production Requirement:
- REQUIRED. The secret must be at least 16 characters, cryptographically random, and kept secure. Every deployed instance must use the same secret so tokens are valid across replicas.
Environment Variables:
ADMIN_ADDRESSES(comma-separated Stellar public addresses)
What Uses It:
AdminGuard— protecting admin-only endpoints (event ingestion, escrow reconciliation, IPFS operations, migrations)- Tested against the authenticated user's wallet address (from JWT token)
Behavior When Unset or Empty:
- Every admin-only route returns HTTP 403 Forbidden
- Admin actions (start event ingestion, trigger reconciliation, manage IPFS pins) are not accessible
- A warning is logged at startup
Behavior When Down:
- No external service; configuration is read at startup
- If an admin address is removed from the list, existing tokens remain valid but new actions are denied
Production Requirement:
- RECOMMENDED. While not strictly required (defaults to deny-all), a deployed backend should have at least one admin address to allow operational tasks. A single-instance dev setup can leave it unset for simplicity, but any production deployment needs at least one admin.
Environment Variables:
DISCORD_WEBHOOK_URL(Discord webhook URL for notifications)
What Uses It:
DiscordService— sending dispute notifications to a Discord channel
Behavior When Unset:
- Dispute notifications are not sent
- No errors; the service is a no-op
Behavior When Down (Bad URL or Discord Outage):
- Notification dispatch fails; error is logged but does not block the dispute operation
- A Sentry event is sent if Sentry is configured
Production Requirement:
- OPTIONAL. Useful for monitoring but not critical to backend operations. Disputes are recorded and resolved regardless of whether Discord is notified.
Environment Variables (optional; at least one recommended for production):
IPFS_PINATA_JWT— Pinata API JWTIPFS_WEB3_STORAGE_TOKEN— Web3.Storage API tokenIPFS_INFURA_PROJECT_IDandIPFS_INFURA_PROJECT_SECRET— Infura IPFS project credentials
What Uses It:
IpfsPinningService— persisting deliverables and proof artifacts to decentralized storage- Failover across multiple providers (tries Pinata, Web3.Storage, Infura in order)
- Simulated in-memory pinning when no credentials are provided
Behavior When Unset:
- Falls back to simulated (in-memory) pinning
- Pins are not persisted to IPFS; lost on restart
GET /ipfs/pinsreturns empty list- No errors; the service simulates success
Behavior When Down (Network Error or API Outage):
- Pinning operation fails
- Service tries next provider in failover chain
- If all providers fail, error is logged and returned to caller (deliverable submission fails)
Production Requirement:
- RECOMMENDED. A production deployment should configure at least one IPFS provider to ensure deliverable artifacts are persisted and retrievable. A local dev setup can use simulated pinning.
Environment Variables:
SENTRY_DSN(Sentry project DSN URL)
What Uses It:
SentryService— capturing and reporting unhandled exceptions and errors- Integrated via
SentryExceptionFilter(catches all unhandled exceptions)
Behavior When Unset:
- Errors are logged locally via NestJS logger but not sent to Sentry
- No external error reporting
- Application continues normally
Behavior When Down (Invalid DSN or Sentry Outage):
- Error sending to Sentry fails silently; errors are still logged locally
- Application is not affected
Production Requirement:
- RECOMMENDED (not required). Useful for monitoring and debugging production errors. A local dev setup can skip it; a production deployment should configure it to track unexpected errors.
For a production deployment, the following must be configured:
- ✅
REDIS_URL— working Redis instance (durability and backup are an infrastructure choice, not an application one) - ✅
JWT_SECRET— at least 16 cryptographically-random characters, kept secure - ✅
ADMIN_ADDRESSES— at least one Stellar address for operational tasks - ✅
STELLAR_HORIZON_URLandSOROBAN_RPC_URL— working endpoints (can use public testnet/mainnet URLs) - ✅
TRUSTFLOW_CONTRACT_ID— deployed contract address on the target network
Recommended additions:
CORS_ORIGIN— restrict API access to known frontend originsDATABASE_URLorDB_HOST/DB_NAME— prepare for future domain service adoptionIPFS_PINATA_JWTorIPFS_WEB3_STORAGE_TOKEN— persist deliverable artifactsSENTRY_DSN— track production errorsDISCORD_WEBHOOK_URL— get notified of disputes
For local development without external dependencies, configure:
NODE_ENV=development
PORT=3001
JWT_SECRET=<ignored; test default used>
ADMIN_ADDRESSES=GADMIN1111111111111111111111111111111111111111111111111111111 # any testnet addressThis gives you:
- ✅ API authentication and authorization
- ✅ Event ingestion stubs (IPFS simulated, no actual pinning)
- ✅ Admin endpoints (operational commands)
- ❌ No rate limiting (Redis not configured)
- ❌ No escrow durability (state lost on restart)
- ❌ No state sharing across instances
- ❌ No event persistence (lost on restart)
Degradation summary:
- Escrow state is per-process, lost on restart
- Nonce validation is per-process (replay-attack vulnerability in tests only)
- Rate limiting is disabled
- IPFS pins are simulated in-memory (no actual persistence)
This setup is suitable for feature development and testing, but not production.
The application logs one line per dependency when starting (see app.setup.ts):
[Nest] 12345 - 09/26/2026, 10:00:00 AM LOG [AppBootstrap] Dependencies
redis: connected | degraded | disabled
database: configured | not-configured
soroban-rpc: healthy | unhealthy | default-endpoint
horizon-rpc: healthy | unhealthy | default-endpoint
admin: configured | warn (no admins)
ipfs: active | simulated
Each line lets an operator quickly verify what is available and whether the deployment matches expectations.
SETUP_INSTRUCTIONS.md— step-by-step deployment guide.env.example— all environment variables with defaults and descriptionsPERSISTENT_STORAGE_SPIKE.md— decision on Redis for escrows (vs. relational DB)app.setup.ts— dependency initialization and health checks