203 lines
7.7 KiB
Markdown
203 lines
7.7 KiB
Markdown
---
|
|
title: System Architecture
|
|
tags: [architecture, system, overview]
|
|
created: 2026-05-23
|
|
---
|
|
|
|
# System Architecture
|
|
|
|
End-to-end architecture for the **Amn** escrow marketplace platform — a two-repo system (frontend + backend) that brokers crypto-escrowed transactions between buyers and sellers.
|
|
|
|
> [!info]
|
|
> Read [[Backend Architecture]] and [[Frontend Architecture]] for component-level detail. Read [[Infrastructure]] for deployment topology.
|
|
|
|
---
|
|
|
|
## 1. High-level topology
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
Browser[Browser / PWA]
|
|
CDN[Static CDN]
|
|
Nginx[Nginx Reverse Proxy<br/>:80/:443]
|
|
FE[Next.js Frontend<br/>standalone server<br/>:8083]
|
|
BE[Express Backend<br/>+ Socket.IO<br/>:5001]
|
|
Mongo[(MongoDB 8)]
|
|
Redis[(Redis 8)]
|
|
SHK[SHKeeper<br/>Crypto Gateway]
|
|
SMTP[SMTP<br/>Nodemailer]
|
|
OAI[OpenAI API]
|
|
BC[Blockchain RPC<br/>Alchemy / WalletConnect]
|
|
|
|
Browser -->|HTTPS + WSS| CDN
|
|
Browser -->|HTTPS| Nginx
|
|
Nginx --> FE
|
|
Nginx --> BE
|
|
FE -->|REST /api/*| BE
|
|
FE -.->|Socket.IO| BE
|
|
BE --> Mongo
|
|
BE --> Redis
|
|
BE -->|Pay-in / Pay-out| SHK
|
|
SHK -.->|Webhook HMAC| BE
|
|
BE --> SMTP
|
|
BE --> OAI
|
|
FE -->|Wallet Connect| BC
|
|
BE -->|Tx verify| BC
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Request lifecycle (typical authenticated REST call)
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
actor U as User
|
|
participant FE as Frontend (Next.js)
|
|
participant AX as Axios Client
|
|
participant BE as Backend (Express)
|
|
participant MW as Middleware Chain
|
|
participant SVC as Service Layer
|
|
participant DB as MongoDB
|
|
participant SK as Socket.IO
|
|
|
|
U->>FE: Interact with UI
|
|
FE->>AX: useMutation(...).mutate(payload)
|
|
AX->>AX: Attach Authorization: Bearer <jwt>
|
|
AX->>BE: POST /api/marketplace/requests
|
|
BE->>MW: helmet, cors, body-parser
|
|
MW->>MW: authMiddleware → verify JWT
|
|
MW->>MW: validation middleware
|
|
MW->>SVC: controller invokes service
|
|
SVC->>DB: Mongoose create / update
|
|
DB-->>SVC: document
|
|
SVC->>SK: emitToRoom("user-{id}", "request:created", payload)
|
|
SVC-->>BE: response payload
|
|
BE->>AX: 200 { success, data }
|
|
AX->>FE: React Query cache update
|
|
FE-->>U: UI re-render
|
|
```
|
|
|
|
Concurrent realtime path:
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant FE as Frontend
|
|
participant BE as Backend
|
|
FE->>BE: socket.connect() w/ auth token
|
|
BE-->>FE: socket connected
|
|
FE->>BE: join-user-room <userId>
|
|
BE-->>FE: joined user-{userId}
|
|
Note over BE,FE: long-lived connection
|
|
BE-->>FE: emit "notification:received"
|
|
FE->>FE: update notification badge
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Deployment topology
|
|
|
|
Production runs as a single Docker Compose stack (`backend/docker-compose.production.yml`) behind an internal Nginx that proxies to both the frontend and backend containers. Watchtower watches the container registry (`git.manko.yoga/manawenuz/escrow-backend`) and auto-pulls new images tagged `latest`.
|
|
|
|
| Layer | Service | Image | Port | Purpose |
|
|
|---|---|---|---|---|
|
|
| Edge | Nginx | `nginx:alpine` | 8083 | Reverse proxy + static assets |
|
|
| App | Frontend | `nickapp-frontend:latest` | 8083 (internal) | Next.js standalone |
|
|
| App | Backend | `nickapp-backend:latest` | 5001 (internal) | Express + Socket.IO |
|
|
| Data | MongoDB | `mongo:8.0` | 27017 (internal) | Primary store |
|
|
| Data | Redis | `redis:8-alpine` | 6379 (internal) | Cache + sessions + rate-limit counters |
|
|
|
|
External SSL termination, DNS, and CDN are assumed to live in front of Nginx (CloudFlare / nginx-proxy / similar).
|
|
|
|
> [!note]
|
|
> Dev uses `backend/docker-compose.dev.yml` (no Nginx, no frontend container — developer runs FE locally with `yarn dev`). See [[Docker Setup]] for full compose breakdown.
|
|
|
|
---
|
|
|
|
## 4. Network ports
|
|
|
|
| Port | Process | Visibility | Notes |
|
|
|---|---|---|---|
|
|
| 8083 | Frontend (Docker) | Public via Nginx | `next start` standalone |
|
|
| 3000 | Frontend (local dev) | localhost | `yarn dev` — hot reload |
|
|
| 5001 | Backend (Express + Socket.IO) | Public via Nginx `/api` & `/socket.io` | One process, two protocols |
|
|
| 27017 | MongoDB | Internal | Mapped to host only in dev |
|
|
| 6379 | Redis | Internal | Mapped to host only in dev |
|
|
| 222 | Gitea SSH | Public | Used for `git clone` |
|
|
|
|
---
|
|
|
|
## 5. Data flow patterns
|
|
|
|
### 5.1 Read path
|
|
|
|
REST `GET` requests are cache-able. React Query on the frontend de-duplicates concurrent requests, retries on failure (exponential backoff), and treats data as stale after `staleTime` (default 60s, varies per query). Backend reads use Mongoose lean queries where possible for performance.
|
|
|
|
### 5.2 Write path
|
|
|
|
Mutations follow optimistic-then-confirm:
|
|
1. Frontend `useMutation` issues the request, often with `onMutate` updating cache optimistically.
|
|
2. Backend validates → writes to MongoDB → emits affected socket rooms → returns canonical response.
|
|
3. Frontend invalidates related query keys; React Query refetches.
|
|
4. Other connected clients receive the socket event and refetch on their side.
|
|
|
|
### 5.3 Webhook path (inbound)
|
|
|
|
External services (SHKeeper) POST to `/api/payment/shkeeper/webhook`. The backend verifies HMAC signature, updates the `Payment` document, advances any linked `PurchaseRequest`/`SellerOffer` state, and emits Socket.IO events to both buyer and seller rooms.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant SHK as SHKeeper
|
|
participant BE as Backend
|
|
participant DB as MongoDB
|
|
participant Buyer
|
|
participant Seller
|
|
SHK->>BE: POST /api/payment/shkeeper/webhook<br/>X-Signature: HMAC-SHA256
|
|
BE->>BE: verifySignature(body, header, SHKEEPER_WEBHOOK_SECRET)
|
|
BE->>DB: Payment.updateOne({providerPaymentId}, {status:"completed"})
|
|
BE->>DB: PurchaseRequest.updateOne(..., {status:"funded"})
|
|
BE-->>Buyer: socket emit "payment:status-updated"
|
|
BE-->>Seller: socket emit "request:funded"
|
|
BE-->>SHK: 200 OK
|
|
```
|
|
|
|
See [[Payment Flow - SHKeeper]] for the full sequence.
|
|
|
|
---
|
|
|
|
## 6. Scaling considerations
|
|
|
|
| Concern | Current state | Scale-out path |
|
|
|---|---|---|
|
|
| Backend stateless? | Yes — JWT-only auth, no in-memory session | Run N replicas behind LB; use Redis pub/sub adapter for Socket.IO |
|
|
| MongoDB | Single-node | Replica set → sharding by `buyerId` |
|
|
| Redis | Single-node | Cluster mode; separate cache vs session DBs |
|
|
| Socket.IO | Single process | `@socket.io/redis-adapter` for multi-node fan-out |
|
|
| File uploads | Local `uploads/` mount | S3 / R2; multer-s3 adapter |
|
|
| Logs | Container stdout | Loki / ELK |
|
|
| Errors | Sentry (`@sentry/nextjs` on FE) | Add Sentry backend SDK |
|
|
|
|
> [!warning]
|
|
> Before horizontal-scaling backend, switch Socket.IO to the Redis adapter — otherwise users on different nodes will not receive each other's events.
|
|
|
|
---
|
|
|
|
## 7. Cross-cutting concerns
|
|
|
|
- **Auth** — Bearer JWT on REST, same token also passed via Socket.IO `auth` payload on connect. See [[Security Architecture]] & [[Authentication Flow]].
|
|
- **i18n** — Frontend supports en/fa/ar/fr/cn/vi via `i18next`. RTL handled by `stylis-plugin-rtl` per direction. See [[Internationalization & RTL]].
|
|
- **Realtime** — All notification/chat/payment state changes broadcast over Socket.IO. See [[Real-time Layer]].
|
|
- **Errors** — Standardized envelope `{ success: false, error: { code, message, details } }` via `backend/src/shared/utils/response-handler.ts`. Sentry on frontend.
|
|
- **Idempotency** — Payment webhooks idempotent by `providerPaymentId` + status. Pay-out uses a client-supplied `reference` string.
|
|
|
|
---
|
|
|
|
## 8. Related documents
|
|
|
|
- [[Backend Architecture]] — module-level walk-through of the Express app
|
|
- [[Frontend Architecture]] — Next.js App Router & section organization
|
|
- [[Infrastructure]] — Docker, compose, registry, Watchtower
|
|
- [[Real-time Layer]] — Socket.IO setup, rooms, events
|
|
- [[Security Architecture]] — auth, hashing, rate-limit, webhook HMAC
|
|
- [[Tech Stack]] — exact versions & purpose of every dependency
|
|
- [[Payment Flow - SHKeeper]] — end-to-end crypto pay-in flow
|