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>
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.
[!tip] Generate JWT_SECRET deterministically per environment so you don't accidentally invalidate sessions when restarting. Store it in your team's secret manager.