Files
nick-doc/10 - Services/frontend.md
Siavash Sameni e52ffce48a docs: sync vault with codebase state (2026-06-12)
- Update backend, frontend, scanner, deployment, amanat-assist service docs
- Update System Overview, Scanner Architecture, Telegram Mini App flow
- Update 10 - Services/README.md
- Add Tenant data model, Tenant API reference, Tenant Storefront Flow
- Add Multi-Shop Branch Project Scan (2026-06-10)
- Add tenant.md service doc
- Append activity log entry
- Reflects archived/search/stats route fix and new E2E test suite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 11:42:18 +04:00

20 KiB
Raw Blame History

title, tags, created, updated
title tags created updated
Frontend Service — amn-frontend
service
frontend
nextjs
react
web3
telegram
2026-06-08 2026-06-12

Frontend Service — amn-frontend

1. Overview

amn-frontend is the primary user-facing application for the Amanat (AMN) escrow marketplace. It serves buyers, sellers, and admins through a unified Next.js 16 App Router application with a Persian-first (RTL) UI.

Field Value
Package name amn-frontend
Version 2.11.89
Status Active — main deployed to dev.amn.gg; feature/white-label-shops deployed to multi.amn.gg
Framework Next.js 16 (App Router + Turbopack), React 19, TypeScript strict
Dev port 8083 (both local and Docker)
Package manager yarn@1.22.22
Node requirement >=20
Repo git@git.tbs.amn.gg:escrow/frontend.git

The app covers the full escrow lifecycle: request creation, multi-seller offer collection, negotiation, on-chain payment (BSC/ETH/Base/TON), delivery confirmation, dispute handling, loyalty points, tenant admin for white-label shops, public seller-shop browsing, and a Telegram Mini App shell for mobile-native access.

[!note] Multi-shop branch feature/white-label-shops adds TenantProvider, /dashboard/admin/tenants, custom-domain controls, bot activation links, and the WEBAPP_ENABLED middleware gate that keeps multi.amn.gg Mini App-first while leaving dashboard/auth routes reachable.


2. Tech Stack

Layer Library / Version Notes
Framework next@^16.1.1 App Router, Turbopack dev server
UI runtime react@^19.1.0, react-dom@^19.1.0 Server + Client Components
Component library @mui/material@^9.0.1 MUI v9 with Emotion; @mui/lab, @mui/x-data-grid, @mui/x-date-pickers, @mui/x-tree-view
Styling engine @emotion/react, @emotion/styled, stylis-plugin-rtl RTL support via stylis
State / data fetching @tanstack/react-query@^5.83.0, swr@^2.3.3 TanStack Query is primary; SWR used in some legacy paths
Real-time socket.io-client@^4.8.1 Bidirectional events; custom SocketContext
Forms react-hook-form@^7.77.0, @hookform/resolvers@^5.0.1, zod@^4.0.10 Schema validation via Zod v4
i18n i18next@^26.3.0, react-i18next@^17.0.8 6 locales (en, fa, ar, fr, cn, vi); RTL for fa/ar
Web3 — EVM wagmi@^2.19.5, viem@^2.31.7, ethers@^6.15.0 WalletConnect + MetaMask + Trezor
Web3 — TON @tonconnect/ui-react@^2.4.4, @ton/core@^0.63.1 TON wallet payments
Hardware wallet @trezor/connect-web@^9.7.3 Trezor signing flow
Chain indexing alchemy-sdk@^3.6.1 Alchemy for multi-chain queries
Rich text editor @tiptap/react@^3.23.6 + extensions Used in post/blog editor
Charts apexcharts@^5.10.1, react-apexcharts@^2.1.0 Dashboard KPI charts
Animation framer-motion@^12.13.0 Page transitions and UI motion
Carousel embla-carousel-react@8.6.0 Product / shop carousels
Maps mapbox-gl@^3.12.0, react-map-gl@^8.0.4 Address / location pickers
HTTP client axios@^1.11.0 Centralised instance with auth interceptors in src/lib/axios.ts
Notifications notistack@^3.0.2, sonner@^2.0.3 Snackbar + toast
Error monitoring @sentry/nextjs@^10.22.0 SDK wraps Next.js build + runtime
CAPTCHA @marsidev/react-turnstile@^1.5.2 Cloudflare Turnstile
Dates dayjs@^1.11.13, date-fns-jalali@^4.1.0-0 Jalali (Persian) calendar support
QR code qrcode@^1.5.4 Wallet payment QR generation
Fonts DM Sans, Inter, Nunito Sans, Public Sans, Barlow Variable fonts via @fontsource-variable

3. App Router Page Structure

All routes live under frontend/src/app/. The dev server and Docker container both bind port 8083.

Top-level route segments

Route Type Purpose
/ Public Landing / marketing home
/api/health API Route Container health-check endpoint
/api/llm API Route LLM proxy for amanat-assist features
/auth/jwt/* Public Sign-in, sign-up, OTP verify, password reset, update
/checkout/request-network/* Public Request Network payment checkout shell
/dashboard/* Protected Main authenticated app (see below)
/design-preview Internal Theme/component sandbox
/error Public Global error display
/payment/callback, /payment/cancel Public Payment gateway redirect landing
/post/[slug] Public Blog post reader
/shop/[seller]/[id] Public Public seller shop / item view
/store/items, /store/checkout Public Storefront browsing and checkout
/telegram Mini App Telegram Mini App shell (see §7)

Dashboard sub-routes (AuthGuard + EmailVerificationGuard)

Route Purpose
/dashboard/dashboard/overview KPI home tiles, recent activity
/dashboard/chat Real-time escrow chat
/dashboard/account/* Profile, address, notifications, wallet, passkey
/dashboard/request/* Buyer purchase requests
/dashboard/request-template/* Seller request templates
/dashboard/payment/* Payment history and detail
/dashboard/points/* Loyalty hub — transactions, referrals, levels
/dashboard/disputes/* Dispute creation and management
/dashboard/seller/* Seller-side offer management
/dashboard/shop-settings/* Seller shop configuration (incl. Telegram config)
/dashboard/shops/* Browse / checkout from within dashboard
/dashboard/user/* Admin user management
/dashboard/post/* Admin blog editor (Tiptap)
/dashboard/admin/tenants/* Tenant admin (white-label shops; feature/white-label-shops only)
/dashboard/assist/* AI assistant (amanat-assist)

4. Key Sections / Features

Marketplace and escrow flow

The primary buyer journey:

  1. Buyer submits a purchase request (/dashboard/request/new) — product description, budget, chain preference.
  2. Sellers see the request and submit offers via request templates (/dashboard/request-template).
  3. Buyer selects an offer; both sides enter the escrow chat (/dashboard/chat).
  4. Buyer initiates payment — on-chain via Wagmi/Trezor or off-chain via Request Network.
  5. After delivery, buyer releases escrow funds; on dispute, both parties access /dashboard/disputes.

Dashboard

Multi-role dashboard accessible post-login. Guards:

  • AuthGuard — redirects unauthenticated users to /auth/jwt/sign-in.
  • EmailVerificationGuard — blocks unverified accounts on key routes.

Sidebar nav adapts to role: buyer, seller, admin, or multi-tenant operator.

Admin

/dashboard/user and /dashboard/post are admin-only sections gated by role check in the layout. Tenant admin (/dashboard/admin/tenants) is only visible on the feature/white-label-shops build.

Telegram Mini App

Full Telegram Mini App (TMA) at /telegram. See §7 for integration details.

White-label shops

feature/white-label-shops branch adds multi-tenancy: TenantProvider (Context), /dashboard/admin/tenants CRUD, custom domain config per tenant, and a WEBAPP_ENABLED middleware flag to route Mini App-first for multi.amn.gg.

Blog / content

Public blog at /post/[slug] rendered server-side. Admin writes posts via Tiptap rich-text editor at /dashboard/post.

AI assistant (amanat-assist)

/api/llm proxies requests to the amanat-assist backend service. The dashboard /assist section provides the in-app chat interface.


5. State Management

Layer Mechanism Usage
Server cache / async state @tanstack/react-query All API data fetching, mutation, background refetch
Legacy async state swr Some older sections not yet migrated to TQ
Real-time events SocketContext (src/contexts/) Socket.io connection; exposes socket via useSocket hook
Global UI state React Context (multiple providers) Auth, Settings (theme/direction/language), Web3
Form state react-hook-form + Zod All forms; validation on client
Zustand Not in use No Zustand dependency in package.json

The root layout stacks providers in order: ThemeProviderSettingsProviderAuthProviderQueryClientProviderSocketContextProviderWeb3Provider.

The Telegram layout uses a minimal provider stack: TonConnectUIProvider + QueryClientProvider only — no dashboard providers.


6. Internationalization

Detail Value
Library i18next@^26.3.0 + react-i18next@^17.0.8
Language detection i18next-browser-languagedetector + accept-language (server hint)
Locales shipped English (en), Persian/Farsi (fa), Arabic (ar), French (fr), Chinese (cn), Vietnamese (vi)
RTL locales fa, ardirection: rtl applied at theme level; stylis-plugin-rtl transforms MUI Emotion styles
Jalali calendar date-fns-jalali@^4.1.0-0 — date pickers switch to Jalali for fa locale
Translation files src/locales/langs/{en,fa,ar,fr,cn,vi}/*.json (lazy-loaded via i18next-resources-to-backend)
Telegram locales src/sections/telegram/locales/{en,fa}.ts — standalone namespace for TMA strings
Default locale Determined by browser; Persian is the primary product locale

RTL layout direction is set in SettingsProvider and passed to the MUI theme. The stylis-plugin-rtl plugin auto-mirrors margin/padding/float/border-radius CSS properties.


7. Telegram Mini App Integration

Loading mechanism

/app/telegram/layout.tsx injects the Telegram SDK via next/script with strategy="beforeInteractive":

<Script src="https://telegram.org/js/telegram-web-app.js" strategy="beforeInteractive" />

No @telegram-apps/sdk npm package is used. The native CDN script approach is chosen for compatibility with Telegram's own versioned releases.

WebApp wrapper

src/utils/telegram-webapp.ts provides a typed wrapper around window.Telegram.WebApp, exposing:

  • initData / initDataUnsafe — raw launch parameters
  • colorScheme, themeParams — Telegram UI theme
  • MainButton, BackButton — native Telegram controls
  • close(), expand(), ready() helper calls

Auth flow

  1. On TMA load, the app extracts initData from window.Telegram.WebApp.
  2. The frontend calls POST /api/auth/telegram with the signed initData string.
  3. Backend verifies the HMAC signature against TELEGRAM_BOT_TOKEN and issues a JWT.
  4. The JWT is stored in memory / cookie, and subsequent API calls use the standard auth header.

Replay protection on this path is intentionally absent — Telegram may reuse initData across reloads. The backend relies on HMAC verification + auth_date freshness only.

TMA route structure

Route Purpose
/telegram Entry point — reads initData, authenticates, redirects
/telegram/shop Seller list and product browsing
/telegram/cart In-app cart and checkout handoff
/telegram/account Account tab (mirrors dashboard/account)

Components

src/sections/telegram/components/ contains TMA-native components:

  • telegram-header.tsx — top navigation bar styled to Telegram theme
  • telegram-chat-row.tsx, telegram-chat-bubble.tsx, telegram-chat-composer.tsx — inline chat UI
  • telegram-request-stepper.tsx — step-through purchase request wizard
  • telegram-cart-fab.tsx — floating cart icon
  • telegram-onboarding-sheet.tsx — first-run onboarding bottom sheet
  • telegram-filter-drawer.tsx, telegram-list-row.tsx, telegram-list-controls.tsx — marketplace list views
  • telegram-theme-toggle.tsx, telegram-language-toggle.tsx — in-app settings
  • telegram-unlinked-state.tsx — shown when no shop is linked to the bot

Shop-settings Telegram config

/dashboard/shop-settings includes a Telegram configuration UI where sellers can:

  • Link their Telegram bot to their shop
  • Set the Mini App URL
  • Preview the bot launch button (TelegramAppButton component)

8. Web3 Integration

EVM (Ethereum / BSC / Base / Polygon / Arbitrum)

Component Detail
Wagmi wagmi@^2.19.5 — React hooks for wallet connection, transaction signing, contract reads
Viem viem@^2.31.7 — low-level EVM client used by wagmi internally
Ethers ethers@^6.15.0 — used in src/web3/web3Service.ts for legacy contract interaction
WalletConnect Project ID via NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID
Alchemy Per-chain API keys (NEXT_PUBLIC_ALCHEMY_API_KEY_{MAINNET,ARBITRUM,BASE,POLYGON,SEPOLIA}) for RPC and indexing
Escrow wallet NEXT_PUBLIC_ESCROW_WALLET_ADDRESS — the platform escrow contract / EOA

Chains supported: Ethereum Mainnet, BSC (BNB Chain), Base, Polygon, Arbitrum, Sepolia (testnet).

Provider hierarchy in src/web3/context/:

  • wagmi-provider.tsx — wraps app in WagmiProvider + QueryClientProvider
  • web3-provider.tsx — DePay + custom payment orchestration layer
  • web3-context.tsx + use-web3-context.ts — React Context for payment state

Trezor

@trezor/connect-web@^9.7.3 handles hardware wallet signing. src/web3/components/web3-signing-card.tsx surfaces the Trezor confirmation UI within the payment flow.

TON

@tonconnect/ui-react@^2.4.4 and @ton/core@^0.63.1 enable TON wallet connections and payments. The Telegram layout wraps the Mini App in TonConnectUIProvider so TON payments work natively within Telegram.

Payment UI components

Component Location
web3-connect-card.tsx Wallet selection / connection modal
web3-payment.tsx Payment execution with status tracking
web3-signing-card.tsx Trezor/hardware wallet signing prompt

Request Network

/app/checkout/request-network/ is the payment shell for Request Network-based payments. The checkout flow is server-side rendered and uses a dedicated layout outside the dashboard guard.


9. CI/CD

Two Woodpecker pipelines run on the CI host at 89.58.32.32 (linux/arm64).

production.ymlmain branch → dev.amn.gg

Trigger: push to main or master.

Step Action
get-version Reads package.json version → writes dev-<version> to .tags
build-and-deploy docker build -t git.tbs.amn.gg/escrow/frontend:dev . then docker compose up -d --no-deps --pull never frontend against /opt/escrow-dev/docker-compose.yml
notify node scripts/ci/tg-notify.cjs → Telegram notification (success/failure)

Image tag: git.tbs.amn.gg/escrow/frontend:dev. No registry push — image is built locally on the CI host. pull_policy: never in the compose override prevents watchtower from pulling a stale remote image.

multi.ymlfeature/white-label-shops → multi.amn.gg

Trigger: push to feature/white-label-shops.

Step Action
build-local docker build with hardcoded NEXT_PUBLIC_* build-args for multi.amn.gg → tags as escrow-multi-frontend:local
deploy docker compose up -d --force-recreate --no-deps frontend against /opt/arcane/data/projects/escrow-multi
notify node scripts/ci/tg-notify.cjs → Telegram notification

[!important] Version bump required Every push that triggers a build must increment the patch version in package.json. Container images are tagged by version — an unchanged version overwrites the previous image and loses history. See RTK.md version policy.

Telegram CI notifications

scripts/ci/tg-notify.cjs is the CI notification script. It reads TG_TOKEN and TG_USERS from Woodpecker secrets. Messages must not use parse_mode (HTML/Markdown) to avoid Telegram API 400 errors from unescaped characters in commit messages.


10. Local Development Quick-Start

# Prerequisites: Node >=20, yarn 1.22.22

cd frontend/

# Install dependencies
yarn install

# Copy and populate env vars
cp .env.local.example .env.local
# Edit .env.local with backend URL, API keys, etc.

# Start dev server (Turbopack, port 8083)
yarn dev

# Alternative: webpack (for debugging Turbopack-specific issues)
yarn dev:webpack

# Type-check
npx tsc --noEmit

# Lint
yarn lint

# Unit tests
yarn test

# E2E tests (requires running backend)
yarn playwright:install   # once
yarn test:e2e

# Production build (outputs standalone server)
yarn build
yarn start

The standalone server output is at .next/standalone/server.js. The build script copies static assets and public folder into the standalone bundle automatically.


11. Environment Variables

All NEXT_PUBLIC_* variables are baked into the client bundle at build time. Server-side and secret variables are runtime-only.

Client-side (build-time baked)

Variable Purpose
NEXT_PUBLIC_API_URL Backend API base URL (e.g. https://dev.amn.gg/api)
NEXT_PUBLIC_BACKEND_URL Backend root URL (used for non-API paths)
NEXT_PUBLIC_APP_URL Canonical frontend URL
NEXT_PUBLIC_SOCKET_URL Socket.io server URL
NEXT_PUBLIC_APP_NAME Display name of the application
NEXT_PUBLIC_APP_VERSION App version string (mirrors package.json version)
NEXT_PUBLIC_ASSETS_DIR Public assets base path
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID WalletConnect Cloud project ID
NEXT_PUBLIC_ALCHEMY_API_KEY_MAINNET Alchemy RPC key — Ethereum Mainnet
NEXT_PUBLIC_ALCHEMY_API_KEY_BASE Alchemy RPC key — Base
NEXT_PUBLIC_ALCHEMY_API_KEY_ARBITRUM Alchemy RPC key — Arbitrum
NEXT_PUBLIC_ALCHEMY_API_KEY_POLYGON Alchemy RPC key — Polygon
NEXT_PUBLIC_ALCHEMY_API_KEY_SEPOLIA Alchemy RPC key — Sepolia testnet
NEXT_PUBLIC_ESCROW_WALLET_ADDRESS Platform escrow wallet / contract address
NEXT_PUBLIC_TELEGRAM_BOT_ID Telegram Bot ID for Mini App auth
NEXT_PUBLIC_TELEGRAM_MINI_APP_URL Deep link URL for TMA launches
NEXT_PUBLIC_TURNSTILE_SITE_KEY Cloudflare Turnstile site key
NEXT_PUBLIC_GOOGLE_CLIENT_ID Google OAuth client ID
NEXT_PUBLIC_MAPBOX_API_KEY Mapbox GL access token
NEXT_PUBLIC_ENABLE_TEST_PAYMENT "true" to show test payment UI
NEXT_PUBLIC_PASSKEY_RP_ID WebAuthn relying party ID
NEXT_PUBLIC_PASSKEY_ORIGIN WebAuthn origin

Multi-stack build-arg overrides (Woodpecker multi.yml)

The multi pipeline passes NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_API_URL, NEXT_PUBLIC_BACKEND_URL, NEXT_PUBLIC_SERVER_URL, NEXT_PUBLIC_SOCKET_URL, NEXT_PUBLIC_PASSKEY_RP_ID, and NEXT_PUBLIC_PASSKEY_ORIGIN as --build-arg to target multi.amn.gg.

[!warning] Two stacks, two bot tokens NEXT_PUBLIC_TELEGRAM_BOT_ID must differ between the escrow-dev and escrow-multi stacks. Sharing a bot token causes Telegram webhook delivery to break for one of the stacks.


12. Known Issues / Open Items

ID Area Description
FE-01 Performance Measured 300800ms API response times on dev.amn.gg are WAN RTT-bound (~235ms), not DB-bound. Server-side requests from loopback :8083 show 312ms. Fix: CDN/edge delivery or server-side rendering that avoids client roundtrips.
FE-02 Cart isolation Global payment socket broadcasts previously wiped every user's cart. Provider gate added in v2.8.4; backend room-scoping remains an open follow-up.
FE-03 Real-time Socket.io rooms are not yet fully scoped by provider on the backend — global broadcast events can still leak cross-user in some edge cases.
FE-04 TMA auth Telegram initData replay protection is intentionally absent. If the threat model changes, a server-side session deduplication layer would be needed at /api/auth/telegram.
FE-05 State migration Some data-fetching paths still use swr rather than @tanstack/react-query. Incremental migration to TQ is ongoing.
FE-06 Multi-chain scanner The AMN scanner payment rail watches specific chains. Cross-chain support (multi-seller + multi-chain) is not fully wired.
FE-07 Trezor @trezor/connect-web requires a popup; CSP and popup-blocker edge cases exist in some Telegram In-App Browser contexts.
FE-08 Pre-push hook The backend repo has a pre-push TSC hook that blocks on full-tree errors; a parallel agent's mid-refactor tree can block clean frontend commits. Always use explicit git add <paths>, never git add -A.
FE-09 CI version policy Every CI-triggering push must bump the patch version. An unchanged version silently overwrites the previous image tag.
FE-10 TON payments TON wallet integration is present but not fully tested end-to-end on mainnet. Verify TON mainnet contract addresses before enabling for buyers.

Last updated: 2026-06-12 — reflects v2.11.89