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>
This commit is contained in:
Siavash Sameni
2026-06-12 11:42:18 +04:00
parent 18073afb52
commit e52ffce48a
18 changed files with 2619 additions and 1102 deletions

View File

@@ -2,7 +2,7 @@
title: Frontend Service — amn-frontend
tags: [service, frontend, nextjs, react, web3, telegram]
created: 2026-06-08
updated: 2026-06-08
updated: 2026-06-12
---
# Frontend Service — amn-frontend
@@ -14,355 +14,305 @@ updated: 2026-06-08
| Field | Value |
|---|---|
| Package name | `amn-frontend` |
| Version | **2.10.5** |
| Status | Active — deployed on `dev.amn.gg` |
| 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` (host runs v26.0.0) |
| Repo | `git@git.manko.yoga:222/nick/frontend.git` |
| 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), delivery confirmation, dispute handling, loyalty points, and a Telegram Mini App shell for mobile-native access.
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
### Core
| Layer | Library / Version | Notes |
|---|---|---|
| Framework | `next@^16.1.1` | App Router, Turbopack dev, standalone output |
| UI runtime | `react@^19.1.0` + `react-dom@^19.1.0` | |
| Language | TypeScript `^6.0.3` strict | `noEmit` check required before push |
| Component library | `@mui/material@^9.0.1` | MUI v9 + `@mui/lab`, `@mui/x-data-grid`, `@mui/x-date-pickers`, `@mui/x-tree-view` |
| Styling | `@emotion/react` + `@emotion/styled` + `stylis-plugin-rtl` | RTL support via stylis |
| Animation | `framer-motion@^12.13.0` | |
| Icon system | `@iconify/react@^6.0.0` | |
### Data Fetching & State
| Layer | Library | Notes |
|---|---|---|
| Server-state cache | `@tanstack/react-query@^5.83.0` | Primary async state manager |
| Lightweight fetch | `swr@^2.3.3` | Used in some hooks alongside RQ |
| HTTP client | `axios@^1.11.0` | Centralized instance with interceptors in `src/lib/axios.ts` |
| Forms | `react-hook-form@^7.77.0` + `zod@^4.0.10` + `@hookform/resolvers@^5.0.1` | |
| Real-time | `socket.io-client@^4.8.1` | `src/contexts/` socket context; used for request/offer/chat events |
### Web3
| Layer | Library | Notes |
|---|---|---|
| Wallet connection | `wagmi@^2.19.5` | Primary Web3 state manager |
| EVM low-level | `viem@^2.31.7` | ABI encoding, RPC calls |
| Compat layer | `ethers@^6.15.0` | Legacy compatibility |
| Chain indexing | `alchemy-sdk@^3.6.1` | Mainnet / Sepolia / Polygon queries |
| TON wallet | `@tonconnect/ui-react@^2.4.4` + `@ton/core@^0.63.1` | TON Connect in Telegram Mini App |
| 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 |
### Internationalization & Localisation
| Layer | Library | Notes |
|---|---|---|
| i18n engine | `i18next@^26.3.0` + `react-i18next@^17.0.8` | |
| Language detection | `i18next-browser-languagedetector@^8.1.0` | |
| Lazy loading | `i18next-resources-to-backend@^1.2.1` | |
| Persian date | `date-fns-jalali@^4.1.0-0` | Jalali calendar date formatting |
| RTL styling | `stylis-plugin-rtl@^2.1.1` | Emotion cache flips properties for RTL |
### Observability & Testing
| Layer | Library | Notes |
|---|---|---|
| Error tracking | `@sentry/nextjs@^10.22.0` | Configured in `src/instrumentation.ts` |
| Unit tests | `jest@^30.4.2` + `@testing-library/react@^16.3.0` | |
| E2E tests | `@playwright/test@^1.56.1` | `e2e/` directory; performance spec included |
| Notifications | `notistack@^3.0.2` + `sonner@^2.0.3` | Toast system |
### Editor & Rich Content
| Layer | Library | Notes |
|---|---|---|
| Rich text | `@tiptap/react@^3.23.6` + extensions | Code blocks, links, images, alignment, underline |
| Markdown render | `react-markdown@10.1.0` + rehype plugins | With GFM, syntax highlight, sanitization |
| Maps | `mapbox-gl@^3.12.0` + `react-map-gl@^8.0.4` | Address / delivery location picker |
| Charts | `react-apexcharts@^2.1.0` | Dashboard KPI charts |
| Carousels | `embla-carousel-react@8.6.0` | Auto-scroll and autoplay plugins |
| 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
The Next.js App Router root is `src/app/`. Pages are thin wrappers that import a View component from `src/sections/<feature>/view/`. No business logic lives in `page.tsx` files.
All routes live under `frontend/src/app/`. The dev server and Docker container both bind port `8083`.
### Top-level routes
### Top-level route segments
| Route segment | Type | Purpose |
| Route | Type | Purpose |
|---|---|---|
| `/` | Public | Landing / marketing page |
| `/api/health` | API route | Health check endpoint |
| `/api/llm` | API route | LLM proxy (amanat-assist integration) |
| `/auth/jwt/*` | Auth | Sign-in, sign-up, verify email, reset password, update password |
| `/checkout/` | Protected | Checkout flow entry (redirects to payment) |
| `/dashboard/` | Protected | Main authenticated shell (see sub-routes below) |
| `/design-preview/` | Dev | Component / theme preview (non-production) |
| `/error/` | Public | Global error page |
| `/payment/` | Protected | Payment status / callback landing |
| `/post/[slug]` | Public | Blog / post reader |
| `/shop/[seller]/[id]` | Public | Public seller shop and product view |
| `/telegram/` | Mini App | Telegram Mini App shell (dedicated layout, see §7) |
| `not-found.tsx` | Public | 404 page |
| `/` | 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 (`/dashboard/*`)
### Dashboard sub-routes (AuthGuard + EmailVerificationGuard)
All dashboard routes are wrapped in `AuthGuard` + `EmailVerificationGuard`.
| Sub-route | Purpose |
| Route | Purpose |
|---|---|
| `account/` | Profile, avatar, address book, notification prefs, passkey, wallet linking |
| `admin/` | Admin control panel |
| `assist/` | AI assistant chat (amanat-assist integration) |
| `chat/` | Real-time escrow negotiation chat |
| `disputes/` | Dispute hub — raise, view, respond |
| `payment/` | Payment history and detail view |
| `points/` | Loyalty hub — transaction log, referral tracking, level tiers |
| `post/` | Admin blog editor (Tiptap) |
| `request/` | Buyer purchase request management (create, track, accept offer) |
| `request-template/` | Seller request templates management |
| `seller/` | Seller profile and analytics |
| `shop-settings/` | Seller shop configuration (name, policies, payment rails) |
| `shops/` | Browse shops / checkout within dashboard scope |
| `user/` | Admin user management |
| `/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
## 4. Key Sections / Features
### Marketplace
### Marketplace and escrow flow
- `src/sections/shop-settings/` — seller configures shop, accepted payment chains/tokens, delivery policy.
- `src/sections/request/` — core escrow lifecycle feature. Status flow:
```
pending_payment → pending → active → received_offers → in_negotiation
→ payment → processing → delivery → delivered → confirming → seller_paid → completed
(or cancelled at most stages)
```
- Shared status/urgency color and label maps live in `src/sections/request/constants.ts`. Do not redefine per-view; use `getStatusColor / getStatusLabel / getUrgencyColor / getUrgencyLabel`.
- Role-based views (buyer / seller / admin) dispatched from `role-based-<feature>-view.tsx` components.
The primary buyer journey:
### Escrow Flow
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`.
The escrow flow spans multiple sections:
### Dashboard
1. **Buyer** creates a purchase request (`/dashboard/request/new`) — wizard in `src/sections/request/components/steps/`.
2. **Sellers** receive notifications via Socket.io and submit offers (`received_offers` state).
3. **Negotiation** phase: real-time chat (`/dashboard/chat/`) with offer counter-proposals.
4. **Payment**: buyer pays on-chain (BSC primary, ETH/Base/Polygon/Arbitrum supported). Funds held in escrow wallet (`NEXT_PUBLIC_ESCROW_WALLET_ADDRESS`). USDT is the primary escrow currency; BSC USDT uses 18 decimals (non-standard — handled in `src/utils/currencyUtils.ts`).
5. **Delivery & confirmation**: seller marks delivered, buyer confirms → `confirming → seller_paid → completed`.
6. **Disputes**: either party can raise at `src/sections/dispute/`.
Multi-role dashboard accessible post-login. Guards:
- `AuthGuard` — redirects unauthenticated users to `/auth/jwt/sign-in`.
- `EmailVerificationGuard` — blocks unverified accounts on key routes.
### Dashboard & Admin
Sidebar nav adapts to role: buyer, seller, admin, or multi-tenant operator.
- Overview tiles with ApexCharts KPI cards.
- Admin panel: user management, shop review, dispute arbitration, blog post management.
- Points / loyalty system: transaction ledger, referral tracking, tier levels at `src/sections/points/`.
- AI assist panel: embedded `amanat-assist` chat at `/dashboard/assist/`.
### 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
See §7 for full detail.
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
The app uses a layered approach — no single global store:
| Layer | Tool | Scope |
| Layer | Mechanism | Usage |
|---|---|---|
| Server state & cache | `@tanstack/react-query` | All API calls — fetching, mutations, invalidation |
| Supplementary fetch | `swr` | Some lightweight hooks |
| Local component state | `React.useState` / `useReducer` | Component-local UI state |
| Cross-tree shared state | React Context | Socket connection (`src/contexts/`), Auth (`src/auth/context/`), Web3, Settings drawer, Localization |
| Form state | `react-hook-form` | All form instances, with `zod` schemas as resolvers |
| Settings (theme/locale) | Context + `localStorage` | Theme mode, layout direction, color preset, font — managed by `src/settings/` |
| 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 |
There is no Zustand or Redux in the dependency tree. Global state is passed via Context providers stacked in `src/app/layout.tsx`.
The root layout stacks providers in order: `ThemeProvider``SettingsProvider``AuthProvider``QueryClientProvider``SocketContextProvider``Web3Provider`.
Key contexts:
- `SocketContext` (`src/contexts/`) — wraps `socket.io-client`, exposes live event subscriptions.
- `AuthContext` (`src/auth/context/`) — JWT session, user object, sign-in/out actions.
- `Web3Context` / wagmi `WagmiProvider` (`src/web3/context/`) — wallet connection, chain switching.
- `SettingsContext` (`src/settings/`) — UI preferences (RTL, color scheme, font).
- `LocalizationProvider` (`src/locales/`) — i18next + MUI date picker locale.
The Telegram layout uses a minimal provider stack: `TonConnectUIProvider` + `QueryClientProvider` only — no dashboard providers.
---
## 6. Internationalization
The app is RTL-first with Persian (Farsi) as the primary production language.
| Aspect | Implementation |
| Detail | Value |
|---|---|
| Engine | `i18next` + `react-i18next` |
| Supported languages | `fa` (Persian), `ar` (Arabic), `en` (English), `fr` (French), `cn` (Chinese), `vi` (Vietnamese) |
| Translation files | `src/locales/langs/<lang>/*.json` — split by feature namespace |
| RTL flip | `stylis-plugin-rtl` applied to the Emotion cache — physical CSS properties (margin-left, padding-right, etc.) are automatically mirrored |
| LTR islands | Inline `dir="ltr"` on elements containing URLs, wallet addresses, token amounts, or other inherently LTR content |
| Persian calendar | `date-fns-jalali` for Jalali date formatting; MUI date pickers use the Jalali locale adapter |
| Direction state | Controlled via `SettingsContext` — users can toggle in the settings drawer |
| Config | `src/locales/locales-config.ts` + `src/locales/i18n-provider.tsx` |
| 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`, `ar``direction: 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 |
Language detection priority: URL `?lng=` param → browser `Accept-Language` → localStorage fallback → `fa`.
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
The Telegram Mini App (TMA) is a first-class feature with a dedicated route segment, layout, and 40+ purpose-built components.
### Loading mechanism
### Loading & Auth Flow
`/app/telegram/layout.tsx` injects the Telegram SDK via `next/script` with `strategy="beforeInteractive"`:
- The TMA loads via Telegram's `webApp.openWebApp()` into the `/telegram/` route.
- The root layout at `src/app/telegram/layout.tsx` provides a minimal provider stack:
- `TonConnectUIProvider` (TON wallet)
- No standard app shell (no top nav, no side drawer) — uses native Telegram chrome instead.
- User identity: `window.Telegram.WebApp.initData` is parsed by `src/utils/telegram-webapp.ts` (a custom wrapper around the `window.Telegram` global — **no `@twa-dev` or `@telegram-apps` SDK package** is used).
- Auth is linked to the existing JWT session: on first open the app prompts the user to connect their AMN account (onboarding sheet). Subsequent opens re-use the stored token.
```tsx
<Script src="https://telegram.org/js/telegram-web-app.js" strategy="beforeInteractive" />
```
### Key File Locations
No `@telegram-apps/sdk` npm package is used. The native CDN script approach is chosen for compatibility with Telegram's own versioned releases.
| Path | Purpose |
### 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 |
|---|---|
| `src/app/telegram/layout.tsx` | TMA root layout — minimal providers |
| `src/app/telegram/page.tsx` | TMA entry point |
| `src/utils/telegram-webapp.ts` | Custom `window.Telegram.WebApp` wrapper / SDK util |
| `src/sections/telegram/` | All TMA feature code |
| `src/sections/telegram/view/` | ~18 view components (one per TMA screen) |
| `src/sections/telegram/components/` | ~28 TMA-specific UI primitives |
| `src/sections/telegram/hooks/` | TMA-scoped hooks including `use-telegram-live-context` |
| `src/sections/telegram/telegram-shell-css.ts` | Native Telegram shell CSS variables integration |
| `/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) |
### TMA Views
### Components
| View file | Screen |
|---|---|
| `telegram-mini-app-view.tsx` | Main shell / router (23 KB — primary orchestrator) |
| `telegram-home-view.tsx` | Home tab |
| `telegram-shop-view.tsx` | Shop list |
| `telegram-seller-shop-view.tsx` | Individual seller shop products |
| `telegram-cart-view.tsx` | Cart |
| `telegram-checkout-view.tsx` | Checkout |
| `telegram-payment-view.tsx` | Payment status |
| `telegram-requests-view.tsx` | Buyer requests list |
| `telegram-request-detail-view.tsx` | Request detail + offer management (31 KB) |
| `telegram-new-request-view.tsx` | New request wizard |
| `telegram-template-detail-view.tsx` | Seller template detail |
| `telegram-chat-view.tsx` | In-app chat thread list |
| `telegram-chat-thread-view.tsx` | Single chat thread |
| `telegram-archived-chats-view.tsx` | Archived chats |
| `telegram-account-view.tsx` | Account settings (18 KB) |
| `telegram-addresses-view.tsx` | Address book (15 KB) |
| `telegram-points-view.tsx` | Loyalty points |
| `telegram-notifications-view.tsx` | Notification centre |
| `telegram-settings-view.tsx` | App settings (14 KB) |
`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
### TMA-specific Components
### Shop-settings Telegram config
Key primitives: `telegram-chat-row`, `telegram-request-stepper`, `telegram-onboarding-sheet`, `telegram-tab-bar`, `telegram-header`, `telegram-quick-actions`, `telegram-cart-fab`, `telegram-support-fab`, `telegram-welcome-banner`, `telegram-unlinked-state`, `telegram-unsupported-state`.
### TON Wallet in TMA
TON Connect (`@tonconnect/ui-react`, `@ton/core`) is active only inside the TMA layout. BSC payments via wagmi/viem are also available in-TMA but TON is the preferred rail for Telegram users.
`/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
All Web3 code lives under `src/web3/`.
### EVM (Ethereum / BSC / Base / Polygon / Arbitrum)
### Architecture
```
src/web3/
├── config.ts # WEB3_CONFIG — chains, WalletConnect project ID
├── index.ts # Public barrel
├── types.ts # Shared Web3 types
├── utils.ts # Misc helpers
├── payment-rails.ts # Chain+token routing logic
├── decentralizedPayment.ts # Core payment execution (16 KB)
├── web3Service.ts # Service layer (9 KB)
├── paymentBackendService.ts # Backend sync after on-chain tx (12 KB)
├── tonconnect-provider.tsx # TonConnect provider wrapper
├── context/ # Web3Context provider
├── contracts/ # ABI definitions
├── hooks/
│ ├── use-web3-wagmi.ts # wagmi-based wallet + tx hooks (5.5 KB)
│ ├── use-alchemy.ts # Alchemy SDK hooks — balance, tx history (3.8 KB)
│ ├── use-chainlink.ts # Chainlink price feed hooks (2.6 KB)
│ └── use-web3-context.ts # Context consumer hook
├── services/ # Additional service modules
├── trezor/ # Trezor Connect integration
└── utils/ # Chain-specific utilities
```
### Supported Chains
Declared in `WEB3_CONFIG.supportedChains`: **BSC** (default, lowest fees), Base, Polygon, Arbitrum, Ethereum.
Primary escrow payments run on BSC. BSC USDT is 18 decimals (non-standard; handled in `src/utils/currencyUtils.ts` — do not hardcode decimals).
### Wallet Support
| Wallet | Integration |
| Component | Detail |
|---|---|
| MetaMask / injected | wagmi `injected()` connector |
| WalletConnect | wagmi WalletConnect connector (`NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID`) |
| Trezor | `@trezor/connect-web` in `src/web3/trezor/` |
| TON wallet | `@tonconnect/ui-react` (TMA only) |
| 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 |
### Oracle / Price Feeds
Chains supported: Ethereum Mainnet, BSC (BNB Chain), Base, Polygon, Arbitrum, Sepolia (testnet).
- Chainlink price feeds via `use-chainlink.ts` — used for USDT/USD peg monitoring.
- Alchemy SDK (`alchemy-sdk`) for on-chain data queries (balances, tx receipts).
- Depeg protection feature in development — see `nick-doc/` oracle depeg protection design doc.
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
### Pipeline
Two Woodpecker pipelines run on the CI host at `89.58.32.32` (`linux/arm64`).
CI is managed by Woodpecker at `frontend/.woodpecker/production.yml`.
### `production.yml` — `main` branch → dev.amn.gg
**Trigger:** push to `main` or `master` branch.
Trigger: push to `main` or `master`.
**Agent:** `platform: linux/arm64` (netcup agent on `89.58.32.32`).
| 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) |
**Steps:**
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.
| Step | Image | Action |
|---|---|---|
| `get-version` | `node:22-alpine` | Reads `package.json` version → writes `dev-<version>` to `.tags` |
| `build-and-deploy` | `docker:27-cli` | `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:22-alpine` | Posts Telegram notification (success or failure) via `scripts/ci/tg-notify.cjs` using `TG_TOKEN` + `TG_USERS` secrets |
### `multi.yml` — `feature/white-label-shops` → multi.amn.gg
**Important CI notes:**
Trigger: push to `feature/white-label-shops`.
- The image is built locally on the host — it does **not** pull from a registry. `docker-compose.override.yml` sets `pull_policy: never`.
- Turbopack is dev-only. The production build uses standard `next build` (webpack).
- `next build` runs a strict TypeScript type-check. The build fails on type errors.
- **Always bump `package.json` version before pushing** to `main`/`master`. Docker tags use `dev-<version>`. Reusing the same version overwrites the previous image tag and breaks rollback.
- A CI green check does not guarantee the image was pushed to the registry. Verify the registry tag manually if deployment seems stale.
| 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 |
### Docker Build
> [!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.
- Output mode: `standalone` (set in `next.config.js`).
- Start command: `PORT=8083 node .next/standalone/server.js`.
- Post-build: `cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/` (required for static assets with standalone output).
- Build cache: `--mount=type=cache` for apk, yarn, and `.next/cache` — incremental Next.js rebuilds on unchanged packages.
### 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.
---
@@ -376,77 +326,93 @@ cd frontend/
# Install dependencies
yarn install
# Copy env file and fill in values
# Copy and populate env vars
cp .env.local.example .env.local
# Edit .env.local — see §11 for required vars
# Edit .env.local with backend URL, API keys, etc.
# Start dev server (Turbopack, port 8083)
yarn dev
# Alternative: webpack (slower, more compatible)
# Alternative: webpack (for debugging Turbopack-specific issues)
yarn dev:webpack
# Type check (must pass before push)
npx tsc --noEmit --ignoreDeprecations 6.0
# Type-check
npx tsc --noEmit
# Lint
yarn lint
yarn lint:fix
# Unit tests
yarn test
# E2E tests (requires running app)
yarn playwright:install
# E2E tests (requires running backend)
yarn playwright:install # once
yarn test:e2e
# Production build (validates types + builds)
# Production build (outputs standalone server)
yarn build
# Run standalone production build
yarn start
```
**Note:** The dev server binds to `http://localhost:8083`. When proxied via infra-caddy on the dev server, it maps to `https://dev.amn.gg`.
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 public vars are prefixed `NEXT_PUBLIC_` and baked into the client bundle at build time.
All `NEXT_PUBLIC_*` variables are baked into the client bundle at build time. Server-side and secret variables are runtime-only.
| Variable | Required | Description |
|---|---|---|
| `NEXT_PUBLIC_APP_NAME` | Yes | Application display name (e.g. `Amanat`) |
| `NEXT_PUBLIC_APP_VERSION` | Yes | App version string — should match `package.json` version |
| `NEXT_PUBLIC_BACKEND_URL` | Yes | Base URL for backend API (e.g. `https://api.dev.amn.gg`) |
| `NEXT_PUBLIC_API_URL` | Yes | API endpoint root (often same as `BACKEND_URL` + `/api`) |
| `NEXT_PUBLIC_SOCKET_URL` | No | Socket.IO server URL — falls back to `NEXT_PUBLIC_BACKEND_URL` |
| `NEXT_PUBLIC_ESCROW_WALLET_ADDRESS` | Yes | On-chain escrow holding wallet address |
| `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID` | Yes | WalletConnect Cloud project ID |
| `NEXT_PUBLIC_ALCHEMY_API_KEY_MAINNET` | Yes | Alchemy API key for Ethereum mainnet |
| `NEXT_PUBLIC_ALCHEMY_API_KEY_SEPOLIA` | Yes | Alchemy API key for Sepolia testnet |
| `NEXT_PUBLIC_ALCHEMY_API_KEY_POLYGON` | Yes | Alchemy API key for Polygon |
| `NEXT_PUBLIC_MAPBOX_API_KEY` | No | Mapbox GL token for map components |
| `NEXT_PUBLIC_ASSETS_DIR` | No | Custom assets base URL — defaults to empty (local `/public`) |
| `BUILD_STATIC_EXPORT` | No | Set `true` to enable static export mode |
| `NODE_ENV` | Auto | Set by Next.js (`development` / `production`) |
### Client-side (build-time baked)
Actual values for the dev deployment are stored in `~/.agentSecrets/escrow/CLAUDE.md` (not in the repo).
| 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
| # | Issue | Status |
| ID | Area | Description |
|---|---|---|
| 1 | **Socket room scoping** — global payment socket broadcasts previously wiped every user's cart. A provider gate was added in frontend `v2.8.4` to filter by provider. Backend-side room scoping is still an open follow-up. | Open |
| 2 | **Backend rate limiter on GET /payment/:id** — `paymentLimiter` (30 req/15 min) applies to the payment status poll endpoint. Results in 429 during rapid callback polling, leaving payments stuck in "processing". Fix is on backend side but frontend polling interval could be increased as a mitigation. | Open (backend fix pending) |
| 3 | **Offer rejection UI** — "all sellers stuck at step 4" was a UI-only bug; backend rejects and notifies correctly. Telegram seller step must use `mojtaba`'s `StepContext` (introduced in `fe v2.9.13`). | Resolved in v2.9.13 |
| 4 | **Cart wipe regression risk** — any new global socket event handler must be scoped by `provider:` to avoid touching RN or other payment records. | Ongoing convention |
| 5 | **Performance is network-bound** — Mongo API profiling shows 300800 ms response times due to WAN RTT (~235 ms). Server-side processing is 312 ms. Frontend-side CDN / edge caching is the recommended fix; DB migration will not help. | Open |
| 6 | **Oracle depeg protection** — server-side oracle quoting for multi-currency pricing + stablecoin depeg protection is designed and approved. Build starts on a new dev branch. | In progress |
| 7 | **Multi-chain for amn.scanner** — the in-house scanner pay-in path is not yet multi-chain; verify scanner watches mainnet addresses before enabling multi-chain selection in the UI for scanner provider. | Open |
| 8 | **Parallel agent pushes** — a second agent (moojttaba) pushes to the same branches. Always `git fetch --rebase` before pushing. Version-bump conflicts are expected. | Ongoing |
| 9 | **Tiptap / rich text in TMA** — the Tiptap editor is desktop-optimised; its usability on mobile Telegram is untested at scale. | Not verified |
| 10 | **`design-preview/` route** — present in the app router but should be excluded or protected in production builds. | Low priority |
| 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*