---
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 live app state primarily to MongoDB, caches in Redis, and brokers all external integrations. The active integration backend also contains the Postgres/Drizzle migration layer, but it is not yet the broad runtime store.

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<br/>(Chrome / Safari / mobile)"]
        Wallet["Wallet extension<br/>(MetaMask / WalletConnect)"]
    end

    subgraph FE["Frontend tier — Next.js 16"]
        SSR["Next.js SSR / RSC<br/>App Router"]
        ClientJS["Client JS<br/>MUI v7 + React 19"]
        Wagmi["Wagmi + Viem<br/>Web3 client"]
        SocketC["socket.io-client"]
        I18n["i18next<br/>6 locales + RTL"]
    end

    subgraph BE["Backend tier — Node.js / Express 5"]
        REST["REST API<br/>/api/*"]
        SocketS["Socket.IO server<br/>rooms per user / chat / request"]
        Auth["Auth service<br/>JWT + Passkey + Google + Telegram"]
        Market["Marketplace service<br/>Requests, Offers, Templates"]
        ChatSvc["Chat service"]
        PaySvc["Payment service<br/>Request Network + ledger + custody controls"]
        TelegramSvc["Telegram service<br/>bot + Mini App + notifications"]
        Disp["Dispute service"]
        Points["Points / Referrals"]
        BlogSvc["Blog service"]
        AISvc["AI service"]
        Notif["Notification service"]
        Files["File upload<br/>(multer + sharp)"]
    end

    subgraph Data["Data tier"]
        Mongo[("MongoDB<br/>via Mongoose<br/>primary runtime")]
        PG[("PostgreSQL 18<br/>Drizzle migration layer")]
        RedisDB[("Redis<br/>cache + locks")]
        Disk[("Local disk<br/>/uploads")]
    end

    subgraph External["External services"]
        Chain["EVM chains<br/>BSC / ETH / Polygon"]
        SMTP["SMTP<br/>(nodemailer)"]
        OpenAI["OpenAI API"]
        Google["Google OAuth"]
        Sentry["Sentry"]
        Alchemy["Alchemy RPC"]
        TelegramAPI["Telegram Bot API<br/>+ Mini App"]
        ReqNet["Request Network<br/>pay-in / webhooks"]
        CFWorker["Durable webhook ingress<br/>(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
    PaySvc -.->|oracle payment_quotes when enabled| PG
    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`.
- **Postgres migration layer** -- backend `2.6.79` includes Drizzle migrations/repos and can persist oracle quote rows to `payment_quotes` when enabled. Payment records, ledger state, wallet destinations, and marketplace entities still flow through Mongo-backed services until the cutover work in [[Postgres Runtime Cutover Status]] is completed.

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-<id>` — personal notifications
- `chat-<id>` — chat room messages, typing indicators, presence
- `request-<id>` — purchase request lifecycle events
- `buyer-<id>` / `seller-<id>` — 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-<id>` 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-<buyerId>` 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.
