--- title: System Overview tags: [overview, architecture, system-map, mermaid] created: 2026-05-23 --- # System Overview > [!info] Scope > This document gives you a single-page map of Amn from browser to blockchain. It is intentionally broad — the goal is for a new developer to walk away knowing what each major box does and how the boxes talk to each other. For deep dives into any subsystem, follow the wikilinks into [[01 - Architecture]]. ## The 10,000-foot view Amn is a **two-repo system**: - **Frontend** (`/Users/mojtabaheidari/code/frontend`) — a Next.js 16 App Router application that serves the marketplace UI, the admin dashboard, the public blog, and the user-facing Web3 wallet flow. - **Backend** (`/Users/mojtabaheidari/code/backend`) — an Express 5 + TypeScript API server that owns all business logic, persists to MongoDB, caches in Redis, and brokers all external integrations. The two repos are deployable independently. They communicate over **HTTPS (REST)** for stateful actions and over **WebSocket (Socket.IO)** for live updates. The frontend never talks directly to MongoDB, Redis, Request Network API keys, OpenAI, or admin custody secrets -- every sensitive external interaction is mediated by the backend so that secrets stay on the server. ## System map ```mermaid flowchart TB subgraph Client["Client tier"] Browser["Browser
(Chrome / Safari / mobile)"] Wallet["Wallet extension
(MetaMask / WalletConnect)"] end subgraph FE["Frontend tier — Next.js 16"] SSR["Next.js SSR / RSC
App Router"] ClientJS["Client JS
MUI v7 + React 19"] Wagmi["Wagmi + Viem
Web3 client"] SocketC["socket.io-client"] I18n["i18next
6 locales + RTL"] end subgraph BE["Backend tier — Node.js / Express 5"] REST["REST API
/api/*"] SocketS["Socket.IO server
rooms per user / chat / request"] Auth["Auth service
JWT + Passkey + Google + Telegram"] Market["Marketplace service
Requests, Offers, Templates"] ChatSvc["Chat service"] PaySvc["Payment service
Request Network + ledger + custody controls"] TelegramSvc["Telegram service
bot + Mini App + notifications"] Disp["Dispute service"] Points["Points / Referrals"] BlogSvc["Blog service"] AISvc["AI service"] Notif["Notification service"] Files["File upload
(multer + sharp)"] end subgraph Data["Data tier"] Mongo[("MongoDB
via Mongoose")] RedisDB[("Redis
cache + locks")] Disk[("Local disk
/uploads")] end subgraph External["External services"] Chain["EVM chains
BSC / ETH / Polygon"] SMTP["SMTP
(nodemailer)"] OpenAI["OpenAI API"] Google["Google OAuth"] Sentry["Sentry"] Alchemy["Alchemy RPC"] TelegramAPI["Telegram Bot API
+ Mini App"] ReqNet["Request Network
pay-in / webhooks"] CFWorker["Durable webhook ingress
(roadmap)"] end Browser --> SSR Browser <--> ClientJS ClientJS <--> SocketC ClientJS --> Wagmi Wagmi <--> Wallet Wallet <--> Chain SSR --> REST ClientJS --> REST SocketC <--> SocketS REST --> Auth & Market & ChatSvc & PaySvc & TelegramSvc & Disp & Points & BlogSvc & AISvc & Notif & Files SocketS --> ChatSvc & Notif & Market Auth & Market & ChatSvc & PaySvc & Disp & Points & BlogSvc & TelegramSvc --> Mongo Auth & PaySvc & Notif --> RedisDB Files --> Disk PaySvc <--> ReqNet ReqNet -.webhook.-> CFWorker CFWorker -.forward/replay.-> PaySvc PaySvc --> Chain PaySvc -.tx fetch.-> Alchemy TelegramSvc <--> TelegramAPI TelegramAPI -.webhook.-> TelegramSvc Auth --> TelegramAPI Notif --> SMTP Auth --> Google AISvc --> OpenAI BE --> Sentry FE --> Sentry ``` ## Walk-through of each subsystem ### Authentication & identity — [[Authentication Flow]] Auth is the gate to every authenticated route. Amn supports four login methods in parallel: - **Email + password (JWT).** Standard `bcrypt`-hashed credentials, access + refresh token pair, six-digit email verification codes, and password reset codes. Source: `backend/src/services/auth/authService.ts`. - **Passkey (WebAuthn).** Platform and cross-platform authenticators are registered against the user account; multiple devices per user are stored in `User.passkeys[]` (`backend/src/models/User.ts:125`). - **Google OAuth.** Server-side verification via `google-auth-library`. See `backend/src/services/auth/googleOAuthService.ts`. - **Telegram (first-class).** `POST /api/auth/telegram` accepts a Telegram Mini App `initData` string or a Telegram Login Widget payload. The backend verifies the Telegram HMAC signature, then signs the user in or auto-creates a new Amanat account with `authProvider: "telegram"` and no required email. This means a user who opens the Telegram Mini App is authenticated with zero sign-up friction. See `backend/src/services/auth/authController.ts` (`telegramAuth`) and [[Authentication Flow#Telegram first-class auth flow]]. Roles are `admin | buyer | seller` (`backend/src/models/User.ts:94`). Role checks happen in route middleware. **Refresh tokens** are stored on the `User` document and rotated. ### Marketplace — [[Marketplace Domain]] The heart of the platform. Three first-class models drive it: - **PurchaseRequest** (`backend/src/models/PurchaseRequest.ts`) — the buyer's brief, with productType (`physical_product | digital_product | service | consultation`), budget range, urgency, delivery info (physical or online), and a long status enum that walks the entire deal: `pending_payment → pending → active → received_offers → in_negotiation → payment → processing → delivery → delivered → confirming → completed`. - **SellerOffer** (`backend/src/models/SellerOffer.ts`) — a single bid attached to a request with `price`, `deliveryTime`, `status`, `validUntil`, and free-form `notes`. - **RequestTemplate** (`backend/src/models/RequestTemplate.ts`) — a reusable "express checkout" version of a purchase request that can spawn real `PurchaseRequest` instances at click time. Services live in `backend/src/services/marketplace/` and are exposed through `/api/marketplace/*`. The frontend uses a mix of React Query (`@tanstack/react-query`) and SWR for data fetching, with mutations gated through the actions layer in `frontend/src/actions/`. ### Payments -- Request Network, Ledger, And Custody Controls Payments are where Amn is most distinctive. The live backend has converged on **Request Network** as the primary provider through a common `Payment` model (`backend/src/models/Payment.ts`) and provider-neutral adapter layer (`backend/src/services/payment/adapters/`): - **Request Network pay-in** -- `/api/payment/request-network`. Creates requests, exposes the Amanat in-house checkout block, and receives signed webhooks (`x-request-network-signature`). Pay-in service: `requestNetworkPayInService.ts`; reconciliation: `requestNetworkReconciliationService.ts`. - **In-house wallet checkout** -- buyer signs the RN-compatible `approve` + `transferFromWithReferenceAndFee` flow from their own wallet, so Rabby/MetaMask wallet UX stays inside Amanat. - **Derived destination wallets** -- `/api/payment/derived-destinations` admin endpoints manage per-`(buyer, sellerOffer, chainId)` receiving addresses, sweep status, and config health. - **Funds ledger** -- `backend/src/services/payment/ledger/` tracks payment detection, holds, releases, refunds, fees, and adjustments independently of provider metadata. - **Release/refund orchestration** -- `/api/payment/:id/(release|refund)` builds instructions; `/confirm` records confirmed transaction hashes. Optional Trezor enforcement gates confirmation when `TREZOR_SAFEKEEPING_REQUIRED=true`. Historical SHKeeper and DePay docs remain in the vault for migration context, but the current backend tree no longer has `backend/src/services/payment/shkeeper/`. The current strategic path is in [[PRD - Decentralized Custody and Smart-Contract Escrow Roadmap]]. ### Real-time chat — [[Chat System]] Chat is built on Socket.IO rooms. Every entity that needs live updates gets its own room (see `backend/src/app.ts:79-178`): - `user-` — personal notifications - `chat-` — chat room messages, typing indicators, presence - `request-` — purchase request lifecycle events - `buyer-` / `seller-` — marketplace-wide updates - `sellers` / `buyers` — global broadcast pools Messages persist to MongoDB through the `Chat` model and are rate-limited per chat (`chatRateLimiter.ts`). The frontend's `socket/` directory wraps `socket.io-client` and exposes typed event hooks to React components. ### Notifications — [[Notifications]] Two notification channels: - **In-app** — `Notification` documents pushed over Socket.IO to `user-` rooms; rendered in the frontend's bell-icon drawer. - **Email** — `nodemailer` + SMTP for verification codes, password resets, and high-importance events. See `backend/src/services/email/`. Push and SMS are tracked as **planned** in `backend/TODO.md`. ### Disputes — [[Dispute System]] When a deal goes wrong (see [[Glossary#Dispute]]), either party can open a dispute. The backend creates a **three-way chat** between buyer, seller, and admin, opens a `Dispute` document with a structured `timeline[]` and `evidence[]`, and can assign the dispute to an admin via `assignAdmin()`. Resolution can be `refund | replacement | compensation | warning_seller | ban_seller | no_action` in the current Mongoose model. > [!note] State alignment gap > The dispute module exists now, but its model still uses the legacy `pending | in_progress | resolved | ...` enum. [[Funds Ledger and Escrow State Machine Specification]] defines the canonical future enum and financial side effects. ### Points & referrals — [[Points System]] Each user has an embedded `points` object (`total | available | used | level`) and `referralStats` (`backend/src/models/User.ts`). Every grant or spend writes a `PointTransaction` record for auditability. The points module supplies referral codes (the `/r/:code` short URL in `app.ts:274` redirects to signup), tracks level progression against `LevelConfig`, and exposes the user-facing dashboard through `frontend/src/sections/points/`. ### Blog — [[Blog System]] A simple admin-authored CMS. `BlogPost` documents support categories, tags, and embedded video via TipTap's rich-text editor on the frontend. Public reads are unauthenticated (`/api/blog/posts`); writes require admin role. Seed data lives in `backend/src/seeds/seedBlogPosts.ts` and runs on dev startup. ### AI — [[AI Assist]] OpenAI (model configurable per call) is exposed through `/api/ai/*`. The current surface includes purchase-request drafting, chat summarisation, and admin-facing intent classification. Requests are queued from the frontend's `actions/ai*` modules and use streaming where appropriate. ### File uploads `multer` accepts multipart uploads (max 10 MB body, `app.ts:232`), `sharp` resizes images on the fly, and files land in `/uploads` (mounted as a static directory at `app.ts:260`). In production the path is configurable via `UPLOAD_PATH`. ### Caching, locks & background jobs **Redis** (`backend/src/services/redis/`) is used for: - short-lived caches (sessions, marketplace listings) - locks used by `PaymentCoordinator` to serialise status transitions - rate-limit counters (currently disabled in code but plumbed in) **Background workers** run inside the Express process for now -- no separate worker tier. Notable timers: - `startPendingPaymentsCleanup()` — sweeps stale unpaid invoices - optional derived-destination sweep cron — sweeps eligible per-payment receiving addresses when configured - Request Network reconciliation — enabled via provider config when the rollout requires fallback status repair - Auto-seed logic on startup (gated by `NODE_ENV` and `AUTO_SEED_ON_START`) ## Request lifecycle (the happy path) > [!example] End-to-end deal walk-through > 1. Buyer signs in (JWT). UI joins `user-` over Socket.IO. > 2. Buyer creates a [[Purchase Request]] → `POST /api/marketplace/requests`. The request lands in `pending`/`active`. Sellers in the matching category receive a Socket.IO notification. > 3. Seller views the request, opens [[Seller Offer]] modal, submits price + delivery time → `POST /api/marketplace/offers`. Buyer sees the offer arrive live. > 4. Buyer accepts an offer → request moves to `payment`. UI opens the payment selector. > 5. Buyer picks **Request Network** -> backend creates a Payment and RN intent, returns an in-house checkout block, and the buyer signs the on-chain payment from their wallet. > 6. Request Network webhook/reconciliation plus the Transaction Safety Provider confirm tx hash, recipient, token, amount, and confirmations before the backend marks escrow funded. > 7. Seller ships. Buyer confirms delivery (or an admin resolves the order/dispute). Admin/custody owners execute release/refund through the release/refund instruction flow. > 8. Both parties leave reviews. Points are awarded. The deal is closed. > > If the buyer disputes the delivery, jump to step 7 of the [[Dispute Flow]] instead. ## Cross-cutting concerns - **Observability** — Sentry is initialised at the very top of `app.ts` (line 2-3) and on the frontend in `sentry.{client,edge,server}.config.ts`. Logs flow through `backend/src/utils/logger.ts`. - **Security** — `helmet`, CORS scoped to `FRONTEND_URL`, JWT with bcrypt-hashed passwords, role-gated middleware. Rate limiting is active (10 req/15 min on auth, 30 on payment, 100 global; Request Network and Telegram webhooks are skip-listed to avoid false limits). - **Internationalisation** — Six locales (en, fr, vi, cn, ar, fa), with `fa` as default. RTL via `stylis-plugin-rtl`. See `frontend/src/locales/`. - **Theming** — MUI v7 with a custom theme in `frontend/src/theme/`. Dark mode is on the roadmap. - **Containerisation** — Docker Compose stacks for dev and prod live in both repos (`docker-compose.dev.yml`, `docker-compose.production.yml`). ## Where to go next - [[Tech Stack]] — exact versions of every dependency. - [[Roles & Personas]] — who does what in the system. - [[Glossary]] — a domain dictionary you will want open in another pane. - [[01 - Architecture]] — service boundaries, module layout, and deployment topology. - [[02 - Data Models]] — MongoDB collections and field-by-field schemas. - [[03 - API Reference]] — every endpoint, its payload, and its auth requirements. - [[04 - Flows]] — diagrammed user journeys for every major use case.