Files
nick-doc/07 - Development/Environment Variables.md
Siavash Sameni 0060b16912 docs: ship in-house RN checkout, scope 5 follow-up tasks (#7-11)
In-house Request Network checkout went fully end-to-end on dev today.
A real 0.01 USDC payment flowed through wallet connect -> approve ->
ERC20FeeProxy.transferFromWithReferenceAndFee -> RN webhook ->
TransactionSafetyProvider -> Payment.status=completed -> page success
state. Tx 0x494c77a29161b5100d8e0b1ac675f1822955d0bb3633ecdbfafb886f84f2f320.

Docs:
- New PRD: Wallet, Multichain, Confirmations, AML, Trezor
  (5 follow-ups, each sized for an independent contributor)
- Updated PRD: Request Network In-House Checkout (phases 0..3 done,
  phase 4 partial, phases 5-6 not started)
- Updated handoff: deployed versions, what is working end-to-end,
  follow-up tasks index

Taskmaster: 5 new top-level tasks (#7..#11) covering ephemeral
destination wallets, multichain proxy registry + USDC/USDT, runtime
confirmation thresholds, optional seller-paid AML screening, and
Trezor signing for admin actions. Tasks are scoped fine-grained so
each is independent enough for kimi to pick up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 15:50:24 +04:00

16 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

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


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 — SHKeeper

SHKeeper is the crypto payment gateway. See Payment Flow and SHKeeper Integration in the architecture section.

Name Repo Required Default Example Purpose
SHKEEPER_BASE_URL backend https://shkeeper.example.com Base API URL
SHKEEPER_API_URL backend https://shkeeper.example.com/api/v1 Versioned API URL
SHKEEPER_API_KEY backend X-Shkeeper-Api-Key header
SHKEEPER_WEBHOOK_SECRET backend HMAC secret for inbound webhook signatures
SHKEEPER_CALLBACK_SECRET backend Older alias for webhook secret; some payloads still use it
SHKEEPER_ALLOWED_TOKENS backend optional USDT,USDC USDT,USDC,BTC Comma-separated list of accepted tokens
SHKEEPER_NETWORKS backend optional bsc,polygon bsc,polygon,eth Networks enabled in checkout
SHKEEPER_ENVIRONMENT backend optional production sandbox Switches SHKeeper sandbox vs prod behaviour
SHKEEPER_FORCE_PAYOUT_DEMO backend optional false true Skips real-chain payout; demo-confirms after 5s
SHKEEPER_FORCE_REAL backend optional false true Forces real-chain even in dev/sandbox
ADMIN_PAYOUT_WALLET_ADDRESS backend for payouts 0xAc23… Wallet that receives platform fees / payouts
ESCROW_WALLET_ADDRESS backend 0xa304… Master escrow address used by payments service
RECEIVER_WALLET_ADDRESS backend optional 0x… Used by alternative payout flows

Payments — Provider Selection

Name Repo Required Default Example Purpose
PAYMENT_PROVIDER backend optional shkeeper request.network Active provider for new payment intents
PAYMENT_DEFAULT_PROVIDER backend optional shkeeper shkeeper Fallback alias when PAYMENT_PROVIDER is unset
PAYMENT_ENABLED_PROVIDERS backend optional shkeeper shkeeper,request.network Comma-separated providers allowed at runtime
PAYMENT_ROLLBACK_PROVIDER backend optional shkeeper shkeeper 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 12 Minimum chain confirmations required by the Transaction Safety Provider.
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 — DePay / Web3 (frontend)

Name Repo Required Default Example Purpose
NEXT_PUBLIC_DEPAY_INTEGRATION_ID frontend for DePay 1330e2d3-… 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 1.0.2 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>"

# SHKeeper (set when ready)
PAYMENT_PROVIDER=shkeeper
PAYMENT_ENABLED_PROVIDERS=shkeeper
PAYMENT_ROLLBACK_PROVIDER=shkeeper
REQUEST_NETWORK_ENABLED=false
PAYMENT_LEDGER_ENFORCEMENT=false
PAYMENT_RECONCILIATION_ENABLED=false
TREZOR_SAFEKEEPING_REQUIRED=false
SHKEEPER_BASE_URL=
SHKEEPER_API_URL=
SHKEEPER_API_KEY=
SHKEEPER_WEBHOOK_SECRET=
SHKEEPER_CALLBACK_SECRET=
SHKEEPER_FORCE_PAYOUT_DEMO=true

# 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=

# 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.