Add 10 - Services/ docs for all sub-projects: backend, frontend, scanner, deployment (new), update amanat-assist. Update Scanner Architecture, Telegram Mini App flow, and Activity Log. Add payment safety edge cases.
467 lines
24 KiB
Markdown
467 lines
24 KiB
Markdown
# Backend Service — amn-backend
|
||
|
||
## 1. Overview
|
||
|
||
**amn-backend** is the Express 5 / TypeScript API server powering the Amanat escrow marketplace (`dev.amn.gg`). It handles all buyer-seller escrow workflow logic, crypto payment processing across multiple chains and providers, real-time socket events, authentication, admin tooling, and the in-progress Mongo→PostgreSQL migration.
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Current version | **2.10.5** |
|
||
| Status | Active — production at `dev.amn.gg` |
|
||
| Repo | `git@git.tbs.amn.gg:escrow/backend.git` |
|
||
| Runtime port | 8083 (production Docker), 8080 (dev Docker), 5001 (dev default) |
|
||
| Database | PostgreSQL (Drizzle ORM) — sole persistence layer as of v2.9.12 |
|
||
| Node version | 22 (`.nvmrc`) |
|
||
|
||
PostgreSQL is the sole active database. MongoDB references remain in some env-var config for the dual-write seam during migration, but no Mongo-backed stores remain active in normal operation (all 11 repository domains use Drizzle repos).
|
||
|
||
---
|
||
|
||
## 2. Tech Stack
|
||
|
||
| Layer | Technology |
|
||
|---|---|
|
||
| Framework | Express 5 (TypeScript) |
|
||
| Runtime | Node.js 22 |
|
||
| Primary DB | PostgreSQL via Drizzle ORM (`drizzle-orm ^0.45.2`, `pg ^8.21.0`) |
|
||
| Migrations | Drizzle Kit (`drizzle-kit ^0.31.1`) — 19 landed SQL migrations |
|
||
| Session / Cache | Redis (`ioredis`) with Socket.IO pub-sub adapter |
|
||
| Realtime | Socket.IO with Redis adapter (seller/buyer rooms) |
|
||
| Auth | JWT (`jsonwebtoken`), Google OAuth, WebAuthn passkeys (`@simplewebauthn/server`), Telegram Mini App initData |
|
||
| Crypto payments | Request Network, amn.scanner (in-house), DePay, SHKeeper |
|
||
| Rate limiting | In-memory (express-rate-limit) — Redis adapter planned |
|
||
| AI integration | OpenAI (listing descriptions, moderation) |
|
||
| Email | Nodemailer via Resend SMTP |
|
||
| Telegram | Bot webhook + Mini App session + identity linking |
|
||
| Security | Helmet, CORS, Cloudflare Turnstile CAPTCHA, HMAC webhook verification |
|
||
| Containerization | Docker (Dockerfile.prod, Dockerfile.dev) |
|
||
| CI/CD | Woodpecker CI (4 pipelines) |
|
||
|
||
---
|
||
|
||
## 3. Directory Structure
|
||
|
||
```
|
||
backend/src/
|
||
├── app.ts # Express bootstrap, middleware chain, route registration, graceful shutdown
|
||
├── cluster.ts # Node.js cluster mode entry point (multi-core)
|
||
├── controllers/ # HTTP request handlers — thin layer, delegate to services
|
||
├── db/ # Drizzle/Postgres layer
|
||
│ ├── schema/ # Per-table Drizzle schema files + index.ts barrel
|
||
│ ├── migrations/ # 19 numbered SQL migration files (0000–0018)
|
||
│ └── repositories/ # Drizzle repos, factory.ts, backfill scripts, verify utilities
|
||
├── infrastructure/
|
||
│ └── socket/ # Socket.IO server init, room helpers, emit wrappers
|
||
├── models/ # Removed — replaced by Drizzle schemas in db/schema/
|
||
├── routes/ # Express Router definitions (mounted in app.ts)
|
||
│ ├── amnScannerWebhookRoutes.ts
|
||
│ ├── blogRoutes.ts
|
||
│ ├── disputeRoutes.ts
|
||
│ └── pointsRoutes.ts
|
||
├── scripts/ # CLI utilities (seed:users, seed:categories, backfill, etc.)
|
||
├── seeds/ # Seed data fixtures (Postgres-capable, store-aware, idempotent)
|
||
├── services/ # Feature domain services (self-contained per domain)
|
||
│ ├── address/ # Address management
|
||
│ ├── admin/ # Admin-only operations, AML config, break-glass, data cleanup
|
||
│ ├── ai/ # OpenAI integration (descriptions, moderation)
|
||
│ ├── auth/ # JWT, OAuth, Passkey, Telegram, password reset
|
||
│ ├── blockchain/ # Web3 read/verify helpers
|
||
│ ├── blog/ # Posts, categories, comments
|
||
│ ├── chat/ # Conversations, messages, attachments
|
||
│ ├── config/ # Runtime config service
|
||
│ ├── delivery/ # Delivery tracking
|
||
│ ├── dispute/ # Dispute lifecycle, evidence, mediator assignment
|
||
│ ├── email/ # Nodemailer transport + templates
|
||
│ ├── file/ # Multer uploads, MIME validation
|
||
│ ├── health/ # Health check endpoint logic
|
||
│ ├── marketplace/ # PurchaseRequest, SellerOffer, Template, Shop
|
||
│ ├── notification/ # Templates, delivery, mark-as-read
|
||
│ ├── payment/ # Payment orchestration + provider adapters + ledger
|
||
│ │ ├── adapters/ # Provider-neutral adapter interface + registry
|
||
│ │ ├── amnScanner/ # amn.scanner in-house pay-in detection
|
||
│ │ ├── ledger/ # Internal funds ledger (available / held / releasable)
|
||
│ │ ├── migration/ # Legacy data backfill utilities
|
||
│ │ ├── observability/ # Logging and incident controls
|
||
│ │ ├── orchestration/ # High-level payment flow coordination
|
||
│ │ ├── priceOracle/ # Chainlink + off-chain FX oracle, depeg protection
|
||
│ │ ├── reconciliation/ # Webhook + status reconciliation per provider
|
||
│ │ ├── request-network/# Request Network routes and webhook signature
|
||
│ │ ├── requestNetwork/ # Request Network service logic
|
||
│ │ ├── safety/ # Transaction Safety Provider + confirmation thresholds
|
||
│ │ ├── tokens/ # On-chain token registry / decimals lookup
|
||
│ │ └── wallets/ # Derived destination wallets + sweep orchestration
|
||
│ ├── points/ # Loyalty points, levels, redemption
|
||
│ ├── redis/ # Redis client, cache helpers, pub-sub
|
||
│ ├── telegram/ # Bot webhook, Mini App session, identity linking, notifications
|
||
│ ├── trezor/ # Trezor hardware-wallet signing for admin approvals
|
||
│ └── user/ # Profile, preferences, addresses
|
||
├── shared/
|
||
│ ├── config/index.ts # Centralised typed env-var loader
|
||
│ ├── middleware/ # authMiddleware, errorHandler, roleGuard, validators
|
||
│ ├── types/ # Cross-cutting TypeScript types
|
||
│ └── utils/response-handler.ts # Standard success/error response envelope
|
||
└── utils/ # Pure utilities (logger, currencyUtils, etc.)
|
||
```
|
||
|
||
Each service folder is self-contained: `<feature>Service.ts`, `<feature>Controller.ts`, `<feature>Routes.ts`, `<feature>Validation.ts`. This design allows future extraction to microservices with minimal coupling.
|
||
|
||
---
|
||
|
||
## 4. Key Services / Modules
|
||
|
||
| Module | Description |
|
||
|---|---|
|
||
| `services/auth/` | JWT issuance/refresh, Google OAuth, WebAuthn passkeys, Telegram initData verification, password reset |
|
||
| `services/marketplace/` | Core escrow domain: PurchaseRequest, SellerOffer, Template, Shop lifecycle |
|
||
| `services/payment/` | Payment orchestration, provider adapters, internal ledger, reconciliation |
|
||
| `services/payment/ledger/` | Double-spend guard: tracks available / held / releasable balances per payment |
|
||
| `services/payment/wallets/` | Derived destination address derivation (xpub) + sweep orchestration |
|
||
| `services/payment/priceOracle/` | Chainlink + off-chain FX oracle for multi-currency pricing + stablecoin depeg protection |
|
||
| `services/payment/safety/` | Transaction Safety Provider: confirmation thresholds, tx hash and transfer match enforcement |
|
||
| `services/payment/amnScanner/` | In-house blockchain scanner webhook adapter (replaces Request Network for pay-in detection) |
|
||
| `services/payment/requestNetwork/` | Request Network pay-in routes, webhook signature verification, invoice creation |
|
||
| `infrastructure/socket/` | Socket.IO server init, buyer/seller room management, emit helpers |
|
||
| `services/redis/` | Redis client wrapper, pub-sub channel helpers, session cache |
|
||
| `services/chat/` | Conversations and message threading between buyer and seller |
|
||
| `services/dispute/` | Dispute lifecycle: open, evidence, mediator, resolution |
|
||
| `services/admin/` | Admin RBAC operations: AML config, break-glass, dispute management, data cleanup |
|
||
| `services/telegram/` | Bot webhook handler, Mini App session auth, Telegram identity linking, push notifications |
|
||
| `services/trezor/` | Trezor hardware-wallet approval gate for high-value admin actions (break-glass overrideable) |
|
||
| `services/notification/` | In-app notification templates, delivery, mark-as-read |
|
||
| `services/ai/` | OpenAI integration: AI-assisted listing descriptions and content moderation |
|
||
| `services/email/` | Nodemailer transport via Resend SMTP, HTML email templates |
|
||
| `services/points/` | Loyalty points engine, tier levels, redemption |
|
||
| `services/blog/` | Blog posts, categories, comments |
|
||
| `services/file/` | Multer-based file upload handler, MIME validation, upload path management |
|
||
| `services/blockchain/` | Low-level Web3 read helpers: balance checks, tx confirmation polling |
|
||
| `db/repositories/` | Drizzle ORM repository layer for all 11 domain entities |
|
||
| `seeds/` | Idempotent Postgres seed fixtures for users, categories, shops, configs |
|
||
| `scripts/` | CLI backfill, migration verify, seeding, and maintenance scripts |
|
||
|
||
---
|
||
|
||
## 5. API Surface Summary
|
||
|
||
All routes are mounted under `/api/*`. See [[03 - API Reference/API Overview]] for the full endpoint reference.
|
||
|
||
Key route groups:
|
||
|
||
| Prefix | Domain |
|
||
|---|---|
|
||
| `/api/auth/*` | Registration, login, OAuth, passkeys, Telegram auth |
|
||
| `/api/payment/*` | Payment CRUD, status polling, provider webhooks |
|
||
| `/api/payment/request-network/*` | Request Network webhook + invoice endpoints |
|
||
| `/api/amn-scanner/*` | amn.scanner webhook receiver |
|
||
| `/api/marketplace/*` | Purchase requests, seller offers, templates |
|
||
| `/api/chat/*` | Conversations, messages, attachments |
|
||
| `/api/dispute/*` | Dispute lifecycle |
|
||
| `/api/admin/*` | Admin operations (role-gated) |
|
||
| `/api/notification/*` | In-app notifications |
|
||
| `/api/blog/*` | Blog posts and comments |
|
||
| `/api/points/*` | Loyalty points |
|
||
| `/api/user/*` | User profile, preferences |
|
||
| `/health` | Docker healthcheck + active store mode listing |
|
||
|
||
**Rate limits (active):**
|
||
|
||
| Scope | Limit |
|
||
|---|---|
|
||
| Auth endpoints | 10 req / 15 min |
|
||
| Payment endpoints | 30 req / 15 min |
|
||
| AI endpoints | 20 req / 15 min |
|
||
| Global | 100 req / 15 min |
|
||
| `GET /api/payment/:id` | Exempt (polling route) |
|
||
| RN + Telegram webhooks | Exempt from global limiter |
|
||
|
||
---
|
||
|
||
## 6. Database
|
||
|
||
### PostgreSQL (primary — active)
|
||
|
||
- **ORM:** Drizzle ORM (`drizzle-orm ^0.45.2`)
|
||
- **Driver:** `pg ^8.21.0`
|
||
- **Migrations:** 19 SQL files under `src/db/migrations/` (0000–0018), managed by `drizzle-kit`
|
||
- **Schemas:** per-table files in `src/db/schema/`, exported via `index.ts` barrel
|
||
- **Repositories:** `src/db/repositories/` — one Drizzle repo per domain; `factory.ts` provides DI
|
||
- **Connection:** `PG_URL` env var (`postgres://user:pass@host:5432/db`)
|
||
- **Migrations run:** `npx drizzle-kit migrate` (or via `drizzle.config.ts`)
|
||
|
||
### MongoDB (legacy — migration in progress)
|
||
|
||
MongoDB and Mongoose were removed at the code level as of v2.9.12. The `MONGO_CONNECT_MODE` env var and `*_STORE` vars remain for the dual-write seam but all active domain stores use Drizzle exclusively. Remaining migration work:
|
||
|
||
- Backfill execution for remaining legacy records
|
||
- Per-domain read cutover verification
|
||
- Chat domain normalization (current blocker)
|
||
- Full runtime coupling severance
|
||
|
||
See [[PRD - Mongo Retirement (Full Nuke).md]] and [[MIGRATION_TODO.md]] for status.
|
||
|
||
---
|
||
|
||
## 7. Auth Model
|
||
|
||
| Method | Mechanism |
|
||
|---|---|
|
||
| Password | bcrypt hashed, JWT access + refresh token pair |
|
||
| Google OAuth | OAuth 2.0 code flow via `google-auth-library` |
|
||
| WebAuthn / Passkeys | `@simplewebauthn/server` — RP ID: `dev.amn.gg` |
|
||
| Telegram Mini App | initData HMAC verification (bot token), replay window: 120 s, TTL: 24 h |
|
||
| Telegram Bot | Webhook secret token header verification |
|
||
| Sessions | Stateless JWT; refresh token stored in Redis |
|
||
| CAPTCHA | Cloudflare Turnstile, triggered after 3 failed login attempts from same IP |
|
||
|
||
**RBAC roles:** `admin`, `buyer`, `seller`, `resolver`, `guard`
|
||
|
||
`roleGuard(role)` middleware is applied per-route after `authMiddleware`. The admin role unlocks break-glass, AML config, dispute management, and data cleanup endpoints.
|
||
|
||
**Trezor safekeeping:** when `TREZOR_SAFEKEEPING_REQUIRED=true`, high-value admin actions (release, refund, payout) require a Trezor-signed approval message. Break-glass overrides this for 1 hour and fires a Telegram alarm.
|
||
|
||
---
|
||
|
||
## 8. Realtime (Socket.IO)
|
||
|
||
- **Adapter:** Redis pub-sub (`@socket.io/redis-adapter`) — scales across multiple backend instances
|
||
- **Init:** `infrastructure/socket/socketService.ts` — attaches to the HTTP server after Express bootstraps
|
||
- **Room model:**
|
||
- `buyer:<userId>` — buyer-facing events (payment status, offer updates, cart)
|
||
- `seller:<userId>` — seller-facing events (new requests, offer accepted)
|
||
- Admin rooms for dispute/notification broadcasts
|
||
- **Auth:** Socket handshake verified with JWT before room join
|
||
- **Known issue:** Global payment broadcasts previously wiped all users' carts (fixed in frontend v2.8.4 with a provider gate). Backend room-scoping is an open follow-up item.
|
||
|
||
Key emitted events (non-exhaustive):
|
||
|
||
| Event | Direction | Description |
|
||
|---|---|---|
|
||
| `payment:status` | Server → client | Payment state change (pending → confirmed → released) |
|
||
| `offer:new` | Server → seller | New purchase request from buyer |
|
||
| `offer:accepted` | Server → buyer | Seller accepted the offer |
|
||
| `notification:new` | Server → client | In-app notification delivery |
|
||
| `dispute:update` | Server → both | Dispute state change |
|
||
| `chat:message` | Server → both | New chat message in conversation |
|
||
|
||
---
|
||
|
||
## 9. Payment Providers
|
||
|
||
The payment layer uses a provider-neutral adapter interface (`services/payment/adapters/`). All providers register in the adapter registry. The ledger (`services/payment/ledger/`) enforces double-spend prevention across all providers.
|
||
|
||
| Provider | Type | Chains | Status |
|
||
|---|---|---|---|
|
||
| **amn.scanner** | In-house blockchain scanner | ETH, BSC, Base, TON | Active — default for new payments when `AMN_SCANNER_DEFAULT=true` |
|
||
| **Request Network** | Decentralized payment protocol | BSC (USDC/USDT) + ETH | Active — legacy in-flight payments; webhook-driven |
|
||
| **DePay** | Widget-based crypto payments | Multi-chain | Available via adapter |
|
||
| **SHKeeper** | Self-hosted crypto gateway | Bitcoin + EVM | Available via adapter |
|
||
|
||
### Payment flow
|
||
|
||
1. Buyer creates intent (`POST /api/payment`) → provider adapter creates invoice / watch address
|
||
2. Provider webhook arrives → HMAC-verified → reconciliation service updates ledger
|
||
3. Escrow holds funds → seller fulfills → admin/resolver releases or refunds
|
||
4. Ledger enforces: held → releasable → released (no double-spend)
|
||
|
||
### amn.scanner specifics
|
||
|
||
- Webhook endpoint: `POST /api/amn-scanner/webhook`
|
||
- HMAC verification via `AMN_SCANNER_WEBHOOK_SECRET`
|
||
- Discriminator field: `payload.event` (not `eventType`) — always check this field
|
||
- Provider scoped by `provider: "amn.scanner"` in payment records
|
||
- Read token decimals on-chain, not from registry
|
||
|
||
### Request Network specifics
|
||
|
||
- Webhook endpoint: `POST /api/payment/request-network/webhook`
|
||
- Webhook secret: `REQUEST_NETWORK_WEBHOOK_SECRET`
|
||
- Network: BSC mainnet, currency: USDC
|
||
- Canonical proxy addresses differ per chain (ETH: `0x370DE2…`, Base: `0x189219…`) — probe before trusting
|
||
|
||
### Safety layer
|
||
|
||
- `TRANSACTION_SAFETY_MIN_CONFIRMATIONS=12` (default)
|
||
- Requires tx hash match and on-chain transfer match before releasing funds
|
||
- AML screening: `none` (default), `ofac` (OFAC SDN list, local, free), or `chainalysis`
|
||
|
||
### Price oracle / depeg protection
|
||
|
||
- Providers: Chainlink + off-chain FX (`OFFCHAIN_FX_URL`)
|
||
- Chains: ETH (RPC via `CHAINLINK_RPC_1`), BSC (via `CHAINLINK_RPC_56`)
|
||
- Depeg hard cap: `DEPEG_HARD_CAP_BPS` (default 500 bps = 5%)
|
||
- Oracle max staleness: `ORACLE_MAX_STALENESS_S=120`
|
||
- Currently disabled (`ORACLE_QUOTING_ENABLED=false`) — enable after FX feeds are configured
|
||
|
||
---
|
||
|
||
## 10. CI/CD (Woodpecker)
|
||
|
||
Four pipelines in `backend/.woodpecker/`:
|
||
|
||
### `production.yml` — primary deploy pipeline
|
||
|
||
Trigger: `push` to `main`/`master` · Platform: `linux/arm64`
|
||
|
||
| Step | Description |
|
||
|---|---|
|
||
| `get-version` | Reads `package.json` version, writes `dev-<version>` to `.tags` |
|
||
| `typecheck` | `npm ci` + `npm run typecheck` — gates image build on clean TypeScript (cached npm on host) |
|
||
| `build-and-deploy` | `docker build -t git.tbs.amn.gg/escrow/backend:dev` locally on the agent, then `docker compose up -d --no-deps --pull never backend` — no registry push, image stays local |
|
||
| `notify` | Posts plain-text result to Telegram via `scripts/ci/tg-notify.cjs` (no parse_mode) |
|
||
|
||
> No registry push on production pipeline — agent is co-located with the stack; pushing large images over Tailscale times out.
|
||
|
||
### `development.yml` — parked
|
||
|
||
Trigger: `event: cron` (no cron configured — effectively disabled). Targets legacy `git.manko.yoga` registry and retired Arcane deploy. Use `manual.yml` for manual playground builds.
|
||
|
||
### `manual.yml` — manual build playground
|
||
|
||
Trigger: manual. Builds and pushes to `git.tbs.amn.gg/escrow/backend`. Used for testing the pipeline independently.
|
||
|
||
### `cleanup.yml` — image cleanup
|
||
|
||
Trigger: scheduled/manual. Removes old image tags from the registry.
|
||
|
||
**Important CI notes:**
|
||
- Always bump `package.json` version before pushing a CI-triggering commit — otherwise the build tag doesn't change and the deployed image may be stale.
|
||
- CI green does not guarantee the image was pushed — verify `git.tbs.amn.gg` has the `dev-<version>` tag before trusting the deploy.
|
||
- Woodpecker eats `${VAR}` in commands — use `$VAR` or `$$VAR`; prefer plugins over raw curl for notifications.
|
||
|
||
---
|
||
|
||
## 11. Local Development Quick-Start
|
||
|
||
```bash
|
||
# Clone and install
|
||
git clone git@git.tbs.amn.gg:escrow/backend.git
|
||
cd backend
|
||
npm install
|
||
|
||
# Copy environment file
|
||
cp .env.example .env.local
|
||
# Edit .env.local — set PG_URL, REDIS_URI, JWT_SECRET at minimum
|
||
|
||
# Start dependencies (Postgres + Redis)
|
||
docker compose -f docker-compose.local.yml up -d
|
||
|
||
# Run DB migrations
|
||
npx drizzle-kit migrate
|
||
|
||
# Start dev server (hot-reload)
|
||
npm run dev
|
||
# → listens on http://localhost:5001
|
||
|
||
# OR run in dev Docker
|
||
docker compose -f docker-compose.dev.yml up
|
||
# → listens on http://localhost:8080
|
||
|
||
# Seed database
|
||
npm run seed:users
|
||
npm run seed:categories
|
||
```
|
||
|
||
**Typecheck (required before push):**
|
||
```bash
|
||
npm run typecheck
|
||
```
|
||
A pre-push git hook blocks the push on tsc errors. If a parallel agent's mid-refactor tree has errors, use explicit `git add <path>` — never `git add -A`.
|
||
|
||
**Run tests:**
|
||
```bash
|
||
npm test
|
||
```
|
||
Test files live in `__tests__/`.
|
||
|
||
---
|
||
|
||
## 12. Environment Variables
|
||
|
||
| Variable | Description |
|
||
|---|---|
|
||
| `NODE_ENV` | `production` / `development` / `test` |
|
||
| `PORT` | HTTP listen port (default 5001) |
|
||
| `TRUST_PROXY_HOPS` | Number of reverse-proxy hops in front of app |
|
||
| `FRONTEND_URL` | Allowed CORS origin for frontend |
|
||
| `BACKEND_URL` | Public backend base URL |
|
||
| `PG_URL` | PostgreSQL connection string |
|
||
| `POSTGRES_USER` | Postgres username (Docker init) |
|
||
| `POSTGRES_PASSWORD` | Postgres password (Docker init) |
|
||
| `POSTGRES_DB` | Postgres database name (Docker init) |
|
||
| `MONGO_CONNECT_MODE` | `always` / `never` / `optional` — Mongo connection behavior (legacy) |
|
||
| `REDIS_URI` | Redis connection URI |
|
||
| `JWT_SECRET` | HS256 signing secret for access tokens |
|
||
| `JWT_EXPIRES_IN` | Access token TTL (e.g. `7d`) |
|
||
| `REFRESH_TOKEN_EXPIRES_IN` | Refresh token TTL (e.g. `30d`) |
|
||
| `ADMIN_EMAIL` | Bootstrap admin account email |
|
||
| `ADMIN_PASSWORD` | Bootstrap admin account password |
|
||
| `SEED_USERS` | `true` to auto-seed users on dev boot |
|
||
| `SEED_PASSWORD_ADMIN` | Admin seed account password |
|
||
| `SEED_PASSWORD_SUPPORT` | Support seed account password |
|
||
| `SEED_PASSWORD_BUYER` | Buyer seed account password |
|
||
| `SEED_PASSWORD_SELLER` | Seller seed account password |
|
||
| `GOOGLE_CLIENT_ID` | Google OAuth client ID |
|
||
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret |
|
||
| `WEBAUTHN_RP_ID` | WebAuthn relying party ID (e.g. `dev.amn.gg`) |
|
||
| `WEBAUTHN_RP_NAME` | WebAuthn relying party display name |
|
||
| `WEBAUTHN_RP_ORIGIN` | WebAuthn allowed origin |
|
||
| `SMTP_HOST` | SMTP server host |
|
||
| `SMTP_PORT` | SMTP server port |
|
||
| `SMTP_SECURE` | `true` for TLS |
|
||
| `SMTP_USER` | SMTP username |
|
||
| `SMTP_PASS` | SMTP password |
|
||
| `SMTP_FROM` | From address for outgoing email |
|
||
| `RESEND_WEBHOOK_SECRET` | Resend inbound webhook signing secret (`whsec_…`) |
|
||
| `TURNSTILE_SECRET_KEY` | Cloudflare Turnstile server-side secret (empty = CAPTCHA disabled) |
|
||
| `RATE_LIMIT_WINDOW_MS` | Rate limit window in milliseconds |
|
||
| `RATE_LIMIT_MAX_REQUESTS` | Max requests per window (global) |
|
||
| `MAX_FILE_SIZE` | Upload max file size in bytes |
|
||
| `UPLOAD_PATH` | Server-side upload directory |
|
||
| `PAYMENT_PROVIDER_MODE` | `live` / `test` |
|
||
| `PAYMENT_LEDGER_ENFORCEMENT` | `true` to enforce double-spend ledger guard |
|
||
| `ESCROW_WALLET_ADDRESS` | Platform escrow wallet address |
|
||
| `RECEIVER_WALLET_ADDRESS` | Platform receiver wallet address |
|
||
| `REQUEST_NETWORK_ENABLED` | Enable Request Network provider |
|
||
| `REQUEST_NETWORK_API_KEY` | Request Network API key |
|
||
| `REQUEST_NETWORK_NETWORK` | Target chain (`bsc`, `eth`, etc.) |
|
||
| `REQUEST_NETWORK_WEBHOOK_SECRET` | HMAC secret for RN webhook verification |
|
||
| `AMN_SCANNER_URL` | amn.scanner service base URL |
|
||
| `AMN_SCANNER_WEBHOOK_SECRET` | HMAC secret for scanner webhook verification |
|
||
| `AMN_SCANNER_DEFAULT` | `true` to make amn.scanner the default provider |
|
||
| `ORACLE_QUOTING_ENABLED` | Enable on-chain oracle pricing + depeg protection |
|
||
| `PRICE_ORACLE_PROVIDERS` | Comma-separated oracle providers (`chainlink,offchain_fx`) |
|
||
| `ORACLE_MAX_STALENESS_S` | Max oracle data age in seconds |
|
||
| `DEPEG_HARD_CAP_BPS` | Stablecoin depeg hard cap in basis points |
|
||
| `OFFCHAIN_FX_URL` | Off-chain FX rate source URL (required for IRR/TRY) |
|
||
| `CHAINLINK_RPC_1` | Private RPC override for Chainlink on ETH mainnet |
|
||
| `CHAINLINK_RPC_56` | Private RPC override for Chainlink on BSC |
|
||
| `DERIVED_DESTINATION_XPUB` | xPub for derived payment address derivation |
|
||
| `DERIVED_DESTINATION_SWEEP_SIGNER` | Sweep signing mode: `build-only` / `hot-key` / `kms` / `trezor` |
|
||
| `DERIVED_DESTINATION_SWEEP_INTERVAL_MS` | Sweep cron interval in ms (0 = disabled) |
|
||
| `SWEEP_MASTER_PRIVKEY` | Master sweep wallet private key (gas funder) |
|
||
| `TREZOR_SAFEKEEPING_REQUIRED` | `true` to require Trezor approval for admin actions |
|
||
| `TRANSACTION_SAFETY_ENABLED` | Enable transaction safety layer |
|
||
| `TRANSACTION_SAFETY_MIN_CONFIRMATIONS` | Minimum on-chain confirmations before release |
|
||
| `TRANSACTION_SAFETY_AML_PROVIDER` | AML provider: `none` / `ofac` / `chainalysis` |
|
||
| `CHAINALYSIS_API_KEY` | Chainalysis API key (when AML provider = chainalysis) |
|
||
| `TELEGRAM_BOT_TOKEN` | Telegram bot token |
|
||
| `TELEGRAM_WEBHOOK_SECRET_TOKEN` | Telegram webhook secret token header value |
|
||
| `TELEGRAM_INITDATA_MAX_AGE_SEC` | Max age for Telegram initData (default 86400 s) |
|
||
| `TG_NOTIFY_CHATS` | Comma-separated Telegram chat IDs for CI/admin notifications |
|
||
|
||
---
|
||
|
||
## 13. Known Issues / Open Items
|
||
|
||
| Issue | Status | Notes |
|
||
|---|---|---|
|
||
| Mongo→PG migration incomplete | In progress | Chat normalization is the current blocker; read cutover and backfill exec pending |
|
||
| Backend room-scoping for socket events | Open | Frontend provider gate is in place (v2.8.4); backend should scope payment events to `seller:<id>` rooms to prevent cross-user leakage |
|
||
| Rate limit counters are in-memory | Open | Not shared across instances; Redis adapter planned for distributed deployments |
|
||
| Oracle quoting disabled | Open | `ORACLE_QUOTING_ENABLED=false`; requires FX feed configuration before enabling |
|
||
| amn.scanner multi-seller + multi-chain gap | Open | Current scanner watches one chain; multi-seller and multi-chain support not yet verified |
|
||
| Woodpecker development.yml parked | Known | Targets legacy registry; needs repointing to `git.tbs.amn.gg` and new Arcane deploy before re-enabling |
|
||
| Trezor safekeeping off by default | By design | `TREZOR_SAFEKEEPING_REQUIRED=false`; must be enabled explicitly in production once admin xpub is registered |
|
||
| Request Network canonical proxy addresses | Known | RN's CREATE2 canonical-address claim is false for ETH and Base — probe actual address before trusting |
|
||
| JSON assets not copied to dist/ | Fixed (requires postbuild) | `tsc` does not copy `.json` files; explicit `postbuild` copy step required for any `fs.readFileSync` on JSON assets |
|
||
| Parallel agent push conflicts | Operational | mojtaba agent pushes to same branches; always `git fetch --rebase` before pushing; expect version-bump conflicts |
|