Files
nick-doc/07 - Development/Environment Variables.md

25 KiB

title, tags
title tags
Environment Variables
development

Environment Variables

Every environment variable read by either repo. Use this as the canonical reference when filling in a new .env, debugging missing-config errors, or reviewing a PR that touches config.

Sources scanned:

  • Backend: src/shared/config/index.ts, src/app.ts, every process.env.* reference in src/, and .env.sentry.example.
  • Frontend: .env.development, .env.local, .env.production, .env.sentry.example, next.config.ts, all process.env.* references in src/.

[!warning] Many secrets in the checked-in .env.* files of the frontend are publicly visible (Alchemy key, WalletConnect ID, Google OAuth client ID, Sentry DSN). Rotate these immediately if the repo leaks. Anything not marked NEXT_PUBLIC_ is not exposed to the browser.


How env is loaded

Backend

src/shared/config/index.ts calls dotenv.config({ path: '.env.development' }) and then dotenv.config() (default .env). In Docker dev, docker-compose.dev.yml injects env_file: .env.local and in production env_file: .env. There is no fallback: if a required var is missing, the typed access (process.env.JWT_SECRET!) yields undefined and the service crashes on first use.

Frontend

Next.js auto-loads .env, .env.local, .env.development, .env.production in the standard precedence order. Only variables prefixed NEXT_PUBLIC_ are exposed to the browser bundle. The production Dockerfile hard-codes several NEXT_PUBLIC_* values via ENV directives at build time so they are baked into the static bundle (see Docker Setup#frontend-dockerfile).


Database

Name Repo Required Default Example Purpose
MONGODB_URI backend mongodb://mongodb:27017 Mongo connection string (no auth in dev)
DB_NAME backend marketplace Database name appended to the URI
PG_URL backend conditional postgres://amanat:...@postgres:5432/amanat_dev Drizzle runtime DSN. Required before importing PG-backed code such as quoteRepo; does not cut over app domains by itself.
MIGRATION_PG_URL backend migration only postgres://amanat:...@postgres:5432/amanat_dev DSN used by backfill/migration scripts. Guarded by non-prod host allowlist.

In docker-compose.production.yml the Mongo service is mongodb and is reachable as mongodb://mongodb:27017 from the backend container.

[!warning] Postgres cutover flags REPO_* flags exist in the backend repository factory, but broad services still call Mongoose models directly on integrate-main-into-development@3a50dc4. Do not assume setting REPO_DEFAULT=pg or REPO_PAYMENT=pg fully moves live traffic to Postgres without service wiring and verification. See Postgres Runtime Cutover Status.


Cache / Redis

Name Repo Required Default Example Purpose
REDIS_URI backend redis://redis:6379 Connection string used by services/redis
REDIS_PASSWORD backend prod only super-secret Substituted into the prod Redis command line (--requirepass)

In dev, Redis runs without a password. In production the compose entrypoint is redis-server --requirepass "$REDIS_PASSWORD" so include :password@ in REDIS_URI accordingly.


Auth / JWT

Name Repo Required Default Example Purpose
JWT_SECRET backend 64 hex chars HMAC key for access tokens
JWT_EXPIRES_IN backend 1h Access token lifetime
REFRESH_TOKEN_EXPIRES_IN backend 30d Refresh token lifetime
ADMIN_EMAIL backend optional admin@marketplace.com Email of the initial admin created by init-admin
ADMIN_PASSWORD backend optional Moji6364 Password for the initial admin
ADMIN_FIRST_NAME backend optional Admin First name for the seeded admin
ADMIN_LAST_NAME backend optional User Last name for the seeded admin
GOOGLE_CLIENT_ID backend optional ...apps.googleusercontent.com Verifies Google ID tokens server-side

[!warning] Rotate JWT_SECRET only during a maintenance window — every active session is invalidated.


Email / SMTP

Name Repo Required Default Example Purpose
SMTP_HOST backend smtp.zoho.com Outbound mail host
SMTP_PORT backend 465 TCP port (numeric)
SMTP_SECURE backend true true for TLS, false for STARTTLS
SMTP_USER backend no-reply@amn.gg SMTP username
SMTP_PASS backend SMTP password (or app password)
SMTP_FROM backend "AMN" <no-reply@amn.gg> Default From header

Payments — Request Network

Request Network is the current primary payment provider. See PRD - Request Network In-House Checkout, Request Network Integration Constraints, and Escrow Flow.

Name Repo Required Default Example Purpose
REQUEST_NETWORK_ENABLED backend optional true true Enables request.network as an available provider
REQUEST_NETWORK_API_KEY backend cli_... Request Network API credential
REQUEST_NETWORK_API_BASE_URL backend https://api.request.network https://api.request.network Request Network API base URL
REQUEST_NETWORK_ORIGIN backend FRONTEND_URL https://dev.amn.gg Origin sent to Request Network API
REQUEST_NETWORK_MERCHANT_REFERENCE backend <receiver>@eip155:56#...:<token> Encodes receiver, chain, payment reference, and token context
REQUEST_NETWORK_NETWORK backend optional bsc bsc Default checkout network
REQUEST_NETWORK_PAYMENT_CURRENCY backend optional USDT USDC Default checkout token symbol
REQUEST_NETWORK_WEBHOOK_CALLBACK_URL backend https://dev.amn.gg/api/payment/request-network/webhook Provider callback URL
REQUEST_NETWORK_WEBHOOK_SECRET backend HMAC secret for inbound webhook signatures
REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS backend optional false false Allows explicit Request Network test webhooks only for controlled smoke tests
ESCROW_WALLET_ADDRESS backend 0xa304… Master escrow address used by payments service
RECEIVER_WALLET_ADDRESS backend optional 0x… Used by alternative payout flows

Historical SHKeeper keys

SHKEEPER_* variables may still appear in legacy migration docs or old .env files. They are not the current primary checkout path and should not be used for new payment work unless a deliberate legacy-record reconciliation task requires them.


Payments — Provider Selection

Name Repo Required Default Example Purpose
PAYMENT_PROVIDER backend optional request.network request.network Active provider for new payment intents
PAYMENT_DEFAULT_PROVIDER backend optional request.network request.network Fallback alias when PAYMENT_PROVIDER is unset
PAYMENT_ENABLED_PROVIDERS backend optional request.network request.network Comma-separated providers allowed at runtime
PAYMENT_ROLLBACK_PROVIDER backend optional request.network request.network Provider used when selected provider is not enabled
PAYMENT_PROVIDER_MODE backend optional live dry-run Provider mode: live, dry-run, or read-only
REQUEST_NETWORK_ENABLED backend optional false true Adds request.network to enabled providers when no explicit list is set
PAYMENT_REQUEST_NETWORK_COHORT_PERCENT backend optional 0 10 Percent of new checkout cohort eligible for Request Network
REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS backend optional false false Allows x-request-network-test webhook bypass only in explicit test mode. Keep false in dev/prod unless running a controlled smoke test.
TRANSACTION_SAFETY_ENABLED backend optional true true Enables the Transaction Safety Provider gate before Request Network pay-ins are marked completed.
TRANSACTION_SAFETY_REQUIRE_TX_HASH backend optional true true Blocks completion when provider evidence does not include a transaction hash.
TRANSACTION_SAFETY_REQUIRE_TRANSFER_MATCH backend optional true true Requires on-chain token/recipient/amount evidence to match the expected payment.
TRANSACTION_SAFETY_MIN_CONFIRMATIONS backend optional 12 chain floor Fallback minimum confirmations for unknown chains. Known chains use built-in acceptance floors unless a higher admin-configured value exists.
RPC_URL_CHAIN_97 backend optional https://bsc-testnet-rpc.publicnode.com https://bsc-testnet-rpc.publicnode.com Overrides the backend verifier RPC for BSC Testnet (bsc-testnet, bnb-testnet, numeric 97).
BSC_TESTNET_RPC_URL / BNB_TESTNET_RPC_URL backend optional RPC_URL_CHAIN_97 fallback https://... Alternate BSC Testnet RPC override names consumed by the legacy verifier path.
TRANSACTION_SAFETY_AML_PROVIDER backend optional none none AML/sanctions provider adapter name. Non-none values should block until implemented/configured.
PAYMENT_LEDGER_ENFORCEMENT backend optional false true Enforce ledger gates for release/refund
PAYMENT_RECONCILIATION_ENABLED backend optional false true Enable scheduled provider reconciliation jobs
TREZOR_SAFEKEEPING_REQUIRED backend optional false true Optional hardware-signature gate for release/refund confirmation. Only the literal value true enforces Trezor proof.

Payments — AMN Pay Scanner

Backend scanner settings:

Name Repo Required Default Example Purpose
AMN_SCANNER_URL backend required when amn.scanner is enabled http://amn-scanner:8080 Internal scanner service base URL used by amnPayAdapter helpers.
AMN_SCANNER_API_KEY backend prod 64 hex chars Bearer token sent to scanner when scanner SCANNER_API_KEY is configured.
AMN_SCANNER_WEBHOOK_SECRET backend required when amn.scanner is enabled 64 hex chars Shared HMAC key used to verify scanner intent and balance-watch webhooks.
AMN_SCANNER_DEFAULT backend optional false true Makes AMN scanner the default pay-in provider where provider selection allows it.

Scanner service settings:

Name Repo Required Default Example Purpose
SCANNER_API_KEY scanner prod 64 hex chars Bearer token required for all scanner endpoints except /health.
BALANCE_WATCH_TICK_SEC scanner optional 60 60 How often the balance-watch scheduler queries for due watches.
BALANCE_WATCH_BATCH_SIZE scanner optional 50 50 Max due balance watches processed per scheduler tick.
DB_PATH scanner optional ./scanner.db /data/scanner.db SQLite state path for intents, checkpoints, and balance watches.
CHAINS_JSON_PATH scanner optional ./supported-chains.json /app/supported-chains.json Chain registry path.
TOKENS_JSON_PATH scanner optional ./tokens.json /app/tokens.json Token registry path used for token/tokenSymbol balance requests.
SCANNER_ENABLED_CHAINS scanner optional all configured chains 56,1,97 Restricts scanner startup to selected chain ids; dev includes chain 97 for BSC Testnet testing.
RPC_BSC / RPC_ETH / RPC_POLYGON / RPC_ARB / RPC_BASE scanner optional chain config provider URL EVM RPC overrides used by intent scanners and balanceOf reads.

Direct-address balance checks and watches currently support EVM ERC-20 only. Backend code should use checkScannerTokenBalance, createScannerBalanceWatch, and stopScannerBalanceWatch from amnPayAdapter.ts.


Repository Mode Flags (Migration Layer)

Name Repo Required Default Example Purpose
REPO_DEFAULT backend optional mongo dual Fallback repository mode for domains that do not set their own flag. Current broad runtime services are not yet wired through the factory.
REPO_USER backend optional REPO_DEFAULT or mongo dual Intended user/auth repository mode. Requires service wiring before it affects normal requests.
REPO_PAYMENT backend optional REPO_DEFAULT or mongo dual Intended payment/ledger repository mode. Current payment APIs still call Mongoose directly.
REPO_POINTS backend optional REPO_DEFAULT or mongo dual Intended points/referral repository mode. Current points service still calls Mongoose directly.
REPO_MARKETPLACE backend optional REPO_DEFAULT or mongo dual Intended purchase request / seller offer repository mode. Current marketplace services still call Mongoose directly.

Payments — Oracle Quoting / Depeg Protection

Name Repo Required Default Example Purpose
ORACLE_QUOTING_ENABLED backend optional false true Enables server-authoritative seller-offer quoting on /api/payment/request-network/intents.
PRICE_ORACLE_PROVIDERS backend optional chainlink,offchain_fx chainlink,offchain_fx Ordered provider list used by the quote engine.
ORACLE_MAX_STALENESS_S backend optional 120 120 Rejects stale FX/token rates.
ORACLE_DISAGREE_BPS backend optional 100 100 Maximum allowed provider disagreement before the quote is blocked.
DEPEG_HARD_CAP_BPS backend optional 500 500 Blocks automatic quoting beyond this stablecoin depeg.
QUOTE_VALIDITY_S backend optional 90 90 Quote expiry window.
REQUOTE_RECONFIRM_BPS backend optional 50 50 Frontend/backend threshold for buyer reconfirmation after a material re-quote.
OFFCHAIN_FX_URL backend conditional https://fx.example/rates Required when offchain_fx is enabled for fiat currencies without Chainlink coverage.
OFFCHAIN_FX_REQUEST_TIMEOUT_MS backend optional 8000 8000 HTTP timeout for the off-chain FX provider.
CHAINLINK_RPC_1 backend conditional https://... Ethereum RPC for Chainlink stablecoin/USD reads.
CHAINLINK_RPC_56 backend conditional https://... BSC RPC for Chainlink stablecoin/USD reads.

Payments — Wallet UI (frontend)

Name Repo Required Default Example Purpose
NEXT_PUBLIC_DEPAY_INTEGRATION_ID frontend legacy only 1330e2d3-… Historical DePay widget integration ID
NEXT_PUBLIC_ESCROW_WALLET_ADDRESS frontend 0xa304… Escrow address shown to buyers in the wallet flow
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID frontend 283b54dd… WalletConnect v2 project ID
NEXT_PUBLIC_ALCHEMY_API_KEY_MAINNET frontend Alchemy RPC for mainnet
NEXT_PUBLIC_ALCHEMY_API_KEY_POLYGON frontend Alchemy RPC for Polygon
NEXT_PUBLIC_ALCHEMY_API_KEY_SEPOLIA frontend optional Alchemy RPC for Sepolia (testing)

OAuth

Name Repo Required Default Example Purpose
GOOGLE_CLIENT_ID backend optional …apps.googleusercontent.com Verifies Google ID tokens server-side
NEXT_PUBLIC_GOOGLE_CLIENT_ID frontend for Google login …apps.googleusercontent.com Client ID used by Google Identity Services in the browser

OpenAI

Name Repo Required Default Example Purpose
OPENAI_API_KEY backend for AI features sk-… Used by services/ai
OPENAI_DEFAULT_MODEL backend for AI gpt-4o-mini gpt-4o Default chat model
OPENAI_MODEL backend optional falls back to default gpt-4o Per-call override read in legacy paths
OPENAI_MAX_TOKENS backend for AI 1024 4096 Hard cap per request
OPENAI_TEMPERATURE backend for AI 0.7 0.2 Decoded as float

App URLs

Name Repo Required Default Example Purpose
FRONTEND_URL backend http://localhost:8083 Used by CORS, Socket.IO origin, password-reset email links
BACKEND_URL backend optional derived from PORT http://localhost:5001 Used in webhook callbacks & emails
API_URL backend optional ${BACKEND_URL}/api http://localhost:5001/api Self-reference for outbound webhooks
PORT backend 5001 HTTP listen port
TRUST_PROXY backend optional auto-on in prod true Enables app.set('trust proxy', 1) for Nginx
NEXT_PUBLIC_APP_URL frontend http://localhost:8083 Self-URL used in metadata + OG tags
NEXT_PUBLIC_APP_NAME frontend optional AMN ایسکرو آنلاین Display name in nav / titles
NEXT_PUBLIC_APP_VERSION frontend optional package.json 2.8.94 Shown in the version logger
NEXT_PUBLIC_API_URL frontend http://localhost:5001/api Axios base URL
NEXT_PUBLIC_API_BASE_URL frontend optional derived http://localhost:5001 Used by a few legacy callers
NEXT_PUBLIC_BACKEND_URL frontend http://localhost:5001 Used by file URL builders
NEXT_PUBLIC_SERVER_URL frontend optional mirror of backend URL http://localhost:5001 Server-side rendering fallback
NEXT_PUBLIC_SOCKET_URL frontend http://localhost:5001 Socket.IO endpoint
NEXT_PUBLIC_ASSETS_DIR frontend optional "" /assets Prefix for static asset URLs
NEXT_PUBLIC_MAPBOX_API_KEY frontend optional pk.… Mapbox token for delivery map

Rate limiting / files

Name Repo Required Default Example Purpose
RATE_LIMIT_WINDOW_MS backend 900000 Express-rate-limit window
RATE_LIMIT_MAX_REQUESTS backend 100 Requests allowed per window per IP
MAX_FILE_SIZE backend 10485760 (10 MB) Multer upload cap (bytes)
UPLOAD_PATH backend optional /app/uploads /var/uploads Disk path for uploads (mounted volume)

Feature flags / seeding

Name Repo Required Default Example Purpose
AUTO_SEED_ON_START backend optional false true Re-seeds users/addresses/templates on boot if users is empty
SEED_USERS backend optional false true One-shot user seeding flag honoured by seedUsers.ts
FORCE_SEED_TEMPLATES backend optional false true Re-creates request templates even if some exist
BUILD_STATIC_EXPORT frontend optional false true Static export build (currently unused)
NEXT_PUBLIC_IS_DEVELOPMENT frontend optional false true Shows the dev-only banner & debug helpers
NEXT_PUBLIC_ENABLE_DEBUG frontend optional false true Verbose console logging in the browser
NEXT_TELEMETRY_DISABLED frontend optional 0 1 Disables Next.js telemetry

Passkey / WebAuthn (frontend)

Name Repo Required Default Example Purpose
NEXT_PUBLIC_PASSKEY_RP_NAME frontend optional Amn Amn Relying-party display name
NEXT_PUBLIC_PASSKEY_RP_ID frontend optional localhost amn.gg Relying-party origin host
NEXT_PUBLIC_PASSKEY_ORIGIN frontend optional derived https://amn.gg Allowed origin for the WebAuthn challenge

Sentry

Name Repo Required Default Example Purpose
NEXT_PUBLIC_SENTRY_DSN frontend optional https://…ingest.sentry.io/… Browser & server Sentry DSN
SENTRY_ORG frontend build-time manawenuz Used by @sentry/nextjs source-map upload
SENTRY_PROJECT frontend build-time escrow-frontend Sentry project slug
SENTRY_AUTH_TOKEN frontend build-time Auth token for source-map upload (CI secret)
SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING frontend optional 1 Silences known dev warning
SENTRY_SUPPRESS_GLOBAL_ERROR_HANDLER_FILE_WARNING frontend optional 1 Silences known dev warning
SENTRY_DSN backend optional https://…ingest.sentry.io/… Backend Sentry DSN (set in src/config/sentry.ts)

The backend Sentry init runs before any other import (src/app.ts line 1) so DSN must be present in the env at process start.


Quick .env.local template (backend, dev)

NODE_ENV=development
PORT=5001
TRUST_PROXY=false

# Database
MONGODB_URI=mongodb://mongodb:27017
DB_NAME=marketplace

# Cache
REDIS_URI=redis://redis:6379

# Auth
JWT_SECRET=<openssl rand -hex 32>
JWT_EXPIRES_IN=1h
REFRESH_TOKEN_EXPIRES_IN=30d

# URLs
FRONTEND_URL=http://localhost:8083
BACKEND_URL=http://localhost:5001

# Rate limit
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

# Files
MAX_FILE_SIZE=10485760
UPLOAD_PATH=/app/uploads

# SMTP
SMTP_HOST=smtp.example.com
SMTP_PORT=465
SMTP_SECURE=true
SMTP_USER=
SMTP_PASS=
SMTP_FROM="AMN <no-reply@amn.gg>"

# Payments
PAYMENT_PROVIDER=request.network
PAYMENT_ENABLED_PROVIDERS=request.network
PAYMENT_ROLLBACK_PROVIDER=request.network
REQUEST_NETWORK_ENABLED=true
REQUEST_NETWORK_API_KEY=
REQUEST_NETWORK_API_BASE_URL=https://api.request.network
REQUEST_NETWORK_ORIGIN=https://dev.amn.gg
REQUEST_NETWORK_MERCHANT_REFERENCE=
REQUEST_NETWORK_NETWORK=bsc
REQUEST_NETWORK_PAYMENT_CURRENCY=USDC
REQUEST_NETWORK_WEBHOOK_CALLBACK_URL=https://dev.amn.gg/api/payment/request-network/webhook
REQUEST_NETWORK_WEBHOOK_SECRET=
REQUEST_NETWORK_ALLOW_TEST_WEBHOOKS=false
PAYMENT_LEDGER_ENFORCEMENT=true
PAYMENT_RECONCILIATION_ENABLED=false
TREZOR_SAFEKEEPING_REQUIRED=false

# OpenAI (optional)
OPENAI_API_KEY=
OPENAI_DEFAULT_MODEL=gpt-4o-mini
OPENAI_MAX_TOKENS=1024
OPENAI_TEMPERATURE=0.7

# Seeding
AUTO_SEED_ON_START=true

# Wallets
ESCROW_WALLET_ADDRESS=0xa3049825c0785095EEd5E7976E0E539466c84044
ADMIN_PAYOUT_WALLET_ADDRESS=

# Derived destinations (per-(buyer, sellerOffer) RN ephemeral wallets — Task #7)
# Backend ONLY needs the xpub. The master seed must live in KMS/Trezor.
DERIVED_DESTINATION_XPUB=
# Only set DERIVED_DESTINATION_XPRIV when DERIVED_DESTINATION_SWEEP_SIGNER=hot-key
# (dev shortcut). For prod, leave this blank and use the Trezor flow (Task #11).
DERIVED_DESTINATION_XPRIV=
DERIVED_DESTINATION_BASE_PATH=m/44'/60'/0'
DERIVED_DESTINATION_CHAIN_ID=56
DERIVED_DESTINATION_SWEEP_SIGNER=build-only
DERIVED_DESTINATION_MIN_SWEEP_AMOUNT=0
DERIVED_DESTINATION_SWEEP_INTERVAL_MS=300000
DERIVED_DESTINATION_SWEEP_AUTOSTART=true

# Master sweep wallet private key (pays gas for permit() + transferFrom() on non-BSC
# chains; sends BNB gas top-ups on BSC). Should be a dedicated low-balance hot wallet
# — NOT the same key used for escrow release/refund.
SWEEP_MASTER_PRIVKEY=
# BSC gas top-up thresholds (in BNB). If derived address BNB balance is below MIN, top up by TOP_UP.
SWEEP_GAS_MIN_BNB=0.001
SWEEP_GAS_TOP_UP_BNB=0.002

# AMN Pay Scanner (replaces Request Network for pay-in detection)
AMN_SCANNER_URL=
AMN_SCANNER_API_KEY=
AMN_SCANNER_WEBHOOK_SECRET=
AMN_SCANNER_DEFAULT=false

# Oracle quoting / stablecoin depeg protection
# Keep disabled until feeds and the off-chain FX source are configured.
ORACLE_QUOTING_ENABLED=false
PRICE_ORACLE_PROVIDERS=chainlink,offchain_fx
ORACLE_MAX_STALENESS_S=120
ORACLE_DISAGREE_BPS=100
DEPEG_HARD_CAP_BPS=500
QUOTE_VALIDITY_S=90
REQUOTE_RECONFIRM_BPS=50
OFFCHAIN_FX_URL=
OFFCHAIN_FX_REQUEST_TIMEOUT_MS=8000
CHAINLINK_RPC_1=
CHAINLINK_RPC_56=

# OAuth
GOOGLE_CLIENT_ID=

[!tip] Generate JWT_SECRET deterministically per environment so you don't accidentally invalidate sessions when restarting. Store it in your team's secret manager.

[!warning] DERIVED_DESTINATION_XPRIV is a development-only shortcut. In production, set DERIVED_DESTINATION_SWEEP_SIGNER=build-only and pair with Task #11 Trezor signing so the master seed never sits on the backend host.