Files
nick-doc/00 - Overview/System Overview.md
2026-05-23 20:35:34 +03:30

13 KiB

title, tags, created
title tags created
System Overview
overview
architecture
system-map
mermaid
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, SHKeeper, or OpenAI — every external interaction is mediated by the backend so that secrets stay on the server.

System map

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"]
        Market["Marketplace service<br/>Requests, Offers, Templates"]
        ChatSvc["Chat service"]
        PaySvc["Payment service<br/>+ PaymentCoordinator"]
        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")]
        RedisDB[("Redis<br/>cache + locks")]
        Disk[("Local disk<br/>/uploads")]
    end

    subgraph External["External services"]
        SHK["SHKeeper<br/>crypto invoicing"]
        DePay["DePay widget"]
        Chain["EVM chains<br/>BSC / ETH / Polygon"]
        SMTP["SMTP<br/>(nodemailer)"]
        OpenAI["OpenAI API"]
        Google["Google OAuth"]
        Sentry["Sentry"]
        Alchemy["Alchemy RPC"]
    end

    Browser --> SSR
    Browser <--> ClientJS
    ClientJS <--> SocketC
    ClientJS --> Wagmi
    Wagmi <--> Wallet
    Wallet <--> Chain

    SSR --> REST
    ClientJS --> REST
    SocketC <--> SocketS

    REST --> Auth & Market & ChatSvc & PaySvc & Disp & Points & BlogSvc & AISvc & Notif & Files
    SocketS --> ChatSvc & Notif & Market

    Auth & Market & ChatSvc & PaySvc & Disp & Points & BlogSvc --> Mongo
    Auth & PaySvc & Notif --> RedisDB
    Files --> Disk

    PaySvc <--> SHK
    SHK -.webhook.-> PaySvc
    PaySvc --> Chain
    Wagmi --> DePay
    DePay --> Chain
    PaySvc -.tx fetch.-> Alchemy

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

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 — Payments Overview / SHKeeper Integration

Payments are where Amn is most distinctive. The backend supports three payment surfaces routed through a common Payment model (backend/src/models/Payment.ts):

  • SHKeeper/api/payment/shkeeper. Mounted at backend/src/app.ts:327. Issues a fresh wallet address per invoice, polls / webhooks for payment confirmation, and runs through PaymentCoordinator to avoid race conditions where a payment status is updated twice. Health is monitored in the background (shkeeperHealthCheck.ts, started in app.ts:433).
  • Decentralized (Wagmi + DePay)/api/payment/decentralized. The user signs and sends the transfer from their own wallet; the backend then verifies the transaction on-chain via blockchainTxFetcher.ts and the Alchemy SDK.
  • Payout/api/payment/shkeeper/payout. Admin-triggered release of escrow funds to the seller's wallet once delivery is confirmed.

All three surfaces converge on the same Payment record (with direction: 'in' | 'out' | 'refund') and trigger the same downstream events: order status update, notification, points award. Pending payments are auto-cleaned by a background timer started in app.ts:374.

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-appNotification documents pushed over Socket.IO to user-<id> rooms; rendered in the frontend's bell-icon drawer.
  • Emailnodemailer + 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 (backend/src/services/dispute/DisputeService.ts) creates a three-way chat between buyer, seller, and admin, opens a Dispute document with a structured timeline[] and evidence[], and assigns the dispute to an admin via assignAdmin(). Resolution can be refund | replacement | compensation | warning_seller | ban_seller | no_action and is recorded on the dispute itself.

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
  • startShkeeperHealthMonitor() — pings the SHKeeper instance and surfaces alerts
  • 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 RequestPOST /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 SHKeeper → backend creates a SHKeeper invoice, returns a wallet address + QR code. Buyer pays. SHKeeper webhook hits /api/payment/shkeeper/webhook; PaymentCoordinator flips Payment.status = paid and PurchaseRequest.status = processing.
  6. Seller ships. Buyer confirms delivery (or it auto-confirms after the SLA window). Admin triggers (or schedules) a payout → SHKeeper releases USDT to the seller's wallet.
  7. 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.
  • Securityhelmet, CORS scoped to FRONTEND_URL, JWT with bcrypt-hashed passwords, role-gated middleware. Rate limiting is plumbed but currently disabled (see app.ts:227).
  • 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