Files
nick-doc/01 - Architecture/Frontend Architecture.md
Siavash Sameni 4b1d8ea36d docs: Telegram Mini App pass 2 — shop/cart/account parity + frontend arch (v2.8.59)
- 04 - Flows/Telegram Mini App.md: major expansion — TelegramSellerShopView,
  TelegramCartView, TelegramAccountView, useTelegramCart/useTelegramShops hooks,
  full nav model, SDK surface table, shop→cart→checkout handoff flow
- 01 - Architecture/Frontend Architecture.md: add Telegram Mini App section,
  TON Connect dependency, update to v2.8.59
- 09 - Audits/Activity Log.md: new entry for frontend@9bafbbb (v2.8.57–2.8.59)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 10:41:01 +04:00

18 KiB

title, tags, created, updated
title tags created updated
Frontend Architecture
architecture
frontend
nextjs
2026-05-23 2026-06-03

Frontend Architecture

Module-level architecture of the Next.js 16 (App Router) + TypeScript + MUI v9 frontend. The current integration worktree observed locally is on integrate-main-into-development.

[!info] Repo: git@git.manko.yoga:222/nick/frontend.git · Active integration branch observed locally: integrate-main-into-development · Version: 2.8.59 (package.json) · Dev port 3000, Docker port 8083.


1. Folder tree

frontend/src/
├── app/                       # Next.js 16 App Router (server + client islands)
│   ├── layout.tsx             # Root layout — providers, fonts, Sentry
│   ├── (public)/              # Unauthenticated routes
│   │   ├── post/[slug]/       # Blog reader
│   │   └── shop/[seller]/[id] # Public seller / item view
│   ├── auth/jwt/              # sign-in, sign-up, verify, reset, update
│   ├── dashboard/             # AuthGuard + EmailVerificationGuard
│   │   ├── overview/          # KPI / home tiles
│   │   ├── chat/              # Real-time chat
│   │   ├── account/           # Profile, address, notifications, wallet, passkey
│   │   ├── request/           # Buyer purchase requests
│   │   ├── request-template/  # Seller request templates
│   │   ├── payment/           # Payment history / detail
│   │   ├── points/            # Loyalty hub (transactions, referrals, levels)
│   │   ├── disputes/          # Dispute hub
│   │   ├── user/              # Admin user management
│   │   ├── post/              # Admin blog editor
│   │   ├── shop-settings/     # Seller shop config
│   │   └── shops/             # Browse / checkout (dashboard scope)
│   ├── telegram/              # Telegram Mini App shell (see §19)
│   │   ├── layout.tsx         # TMA root — TonConnectUIProvider + minimal providers
│   │   ├── shop/              # Seller list + product browsing
│   │   ├── cart/              # In-shell cart + checkout handoff
│   │   └── account/           # Account tab (dashboard parity)
│   ├── error/                 # Global error page
│   └── not-found.tsx          # 404
├── sections/                  # Page-specific composition modules (one folder per feature)
│   └── (chat|payment|request|request-template|dispute|user|points|telegram|...)
├── components/                # Reusable UI primitives (hook-form, table, upload, editor, ...)
├── layouts/                   # Page-template wrappers (auth-centered, auth-split, dashboard, main, telegram)
├── theme/                     # MUI theme creation, palette, typography, overrides
├── settings/                  # Settings drawer (mode, layout, direction, color, font)
├── contexts/                  # React Context providers (socket-context)
├── hooks/                     # 50+ custom hooks (use-boolean, use-socket, use-web3-wagmi, …)
├── lib/                       # Cross-cutting libs (axios.ts with interceptors)
├── locales/                   # i18next config + langs/{en,fa,ar,fr,cn,vi}/*.json
└── types/                     # Cross-app TypeScript types

2. Rendering strategy

  • App Router with output: 'standalone' in next.config.ts for production single-binary serving.
  • Server components by default, client components opted into with "use client". Heavy interactive pages (chat, editor, dashboard) are mostly client-side; SEO routes (shop/, post/[slug]) leverage server rendering.
  • Turbopack in dev (next dev --turbopack).
  • Streaming via loading.tsx and Suspense boundaries.
  • MUI cache is wired up via @mui/material-nextjs in the root layout to avoid FOUC across server/client boundary.

3. Provider tree (root layout)

flowchart TB
    A[RootLayout]
    A --> B[AppRouterCacheProvider<br/>MUI emotion cache]
    B --> C[ThemeProvider<br/>theme + RTL stylis]
    C --> D[LocalizationProvider<br/>dayjs adapter]
    D --> E[I18nProvider<br/>i18next]
    E --> F[QueryClientProvider<br/>React Query]
    F --> G[SocketProvider<br/>Socket.IO context]
    G --> H[SnackbarProvider<br/>notistack]
    H --> I[Children — routes]

Order matters: theme must wrap query (because mutations show snackbars styled by theme); socket wraps snackbar (so socket-driven notifications can fire snackbars).

The Telegram Mini App shell (app/telegram/) uses its own slimmer layout that replaces the dashboard shell with TonConnectUIProvider and skips the settings drawer (see §19).


4. Route layout & guards

Route group Layout Guard chain
(public) layouts/main none
auth/jwt/* layouts/auth-centered or auth-split redirect if already authed
dashboard/* layouts/dashboard (sidebar + topbar + breadcrumbs) AuthGuardEmailVerificationGuard
dashboard/user/* dashboard + role: admin
dashboard/post/* (editor) dashboard + role: admin
dashboard/shop-settings/* dashboard + role: seller
telegram/* layouts/telegram (bottom-tab shell) Telegram initData token guard + role check

Guards live in frontend/src/auth/ (HOC + hook). They consult the JWT-derived user context and redirect unauthenticated to /auth/jwt/sign-in?returnTo=.... The Telegram guard additionally validates window.Telegram.WebApp.initData before issuing a session.


5. Sections vs components vs hooks

The codebase enforces a three-layer split:

Layer Lives in Purpose Example
Section src/sections/<feature>/ Page-specific composition; orchestrates components sections/chat/view/ChatView.tsx
Component src/components/<name>/ Reusable across sections components/hook-form/RHFTextField.tsx
Hook src/hooks/<name>.ts Encapsulated stateful behavior hooks/use-chat-socket.ts

Tip

Per the cursor rules (backend/.cursor/rules/ui-development-standards.mdc), every component folder has index.ts (barrel export), <name>.tsx (component), classes.ts (styled-component class names), types.ts (interface). Following this layout keeps each component refactorable.


6. State management

The frontend deliberately uses three state mechanisms, each for one concern:

Concern Tool Where
Server data React Query every useXxxQuery / useXxxMutation hook
Cross-page shared state React Context contexts/socket-context.tsx, settings context, auth context
Per-component / local UI useState, useReducer, use-boolean, use-set-state inside components

No Redux, no MobX, no Recoil. The cursor rules also mention Zustand as the preferred client store if one is added, but the dev branch currently relies on React Query + Context.

React Query setup

  • QueryClient created once at the root layout with defaultOptions:
    • queries: { staleTime: 30_000, retry: 1, refetchOnWindowFocus: false }
    • mutations: { retry: 0 }
  • Query keys are tuples — convention: ['<resource>', <filter|id|...>] e.g. ['requests', { status: 'open' }].
  • Mutations invalidate related keys in onSuccess.

7. API client (src/lib/axios.ts)

A single axios instance underpins every HTTP call:

const api = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  withCredentials: true,
});

// Request interceptor — attach token
api.interceptors.request.use((cfg) => {
  const token = getStoredToken();
  if (token) cfg.headers.Authorization = `Bearer ${token}`;
  cfg.headers['X-Request-Id'] = randomUUID();
  return cfg;
});

// Response interceptor — handle 401, normalize errors
api.interceptors.response.use(
  (res) => res.data,
  async (err) => {
    if (err.response?.status === 401 && !retried) {
      // attempt refresh-token flow
      await refresh();
      return api.request(err.config);
    }
    throw normalizeError(err);
  }
);

Endpoint constants live alongside the hook that uses them — no central api/endpoints.ts.


8. Real-time integration

The SocketProvider in contexts/socket-context.tsx:

  1. Opens the connection after authentication (token from storage).
  2. Auto-joins user-specific rooms (user-{id}, seller-{id} or buyer-{id} based on role).
  3. Exposes a useSocket() hook returning socket, connected, helper emitters.

Higher-level hooks build on this:

Hook Subscribes to
use-chat-socket chat:new-message, typing indicators, read receipts
use-conversations conversation list updates
use-notifications notification:received
use-purchase-requests request:offer-received, status changes
use-marketplace-socket broad market events
use-unified-real-time multi-event aggregator

The Telegram Mini App shell reuses the same SocketProvider — live socket updates are available in the TMA shop, cart, and account tabs.

See Real-time Layer for the full event catalog.


9. Web3 integration

// wagmi config (approx — confirm in src/web3/ or src/lib/wagmi.ts)
const config = createConfig({
  chains: [bsc, polygon, mainnet, sepolia],
  transports: {
    [bsc.id]: http(`https://...alchemy.com/${KEY}`),
    [polygon.id]: http(`https://polygon-mainnet.g.alchemy.com/v2/${KEY}`),
    ...
  },
  connectors: [
    injected(),               // MetaMask
    walletConnect({ projectId: NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID }),
  ],
});

Wallet UI: connect / disconnect / show address / show balance via use-web3-wagmi, use-web3-context. The current checkout target is the Request Network in-house flow; the DePay widget package remains legacy/frontier context and should not be treated as the primary path.

TON wallet support is handled separately via @ton/core + @tonconnect/ui-react in the Telegram Mini App layer (see §19).


10. Internationalization

  • i18next + react-i18next initialized in src/locales/locales-config.ts with 6 langs (en, fa, ar, fr, cn, vi).
  • Translation files in langs/<locale>/*.json (e.g., common.json).
  • Direction (ltr|rtl) lives in settings; stylis-plugin-rtl is wired into the MUI cache when dir === 'rtl'.
  • Date formatting via dayjs with locale auto-loaded.
  • Number formatting via Intl.NumberFormat + helper at locales/utils/number-format-locale.ts.
  • DataGrid has Persian-specific locale at custom-fa-data-grid-locale.ts.

See Internationalization & RTL for full detail.


11. Forms & validation

react-hook-form + zod schema via @hookform/resolvers/zod. Custom field wrappers in components/hook-form/:

Wrapper Wraps
RHFTextField MUI TextField
RHFSelect MUI Select
RHFAutocomplete MUI Autocomplete
RHFCheckbox MUI Checkbox
RHFRadioGroup MUI RadioGroup
RHFSwitch MUI Switch
RHFUpload custom Dropzone (components/upload)
RHFEditor TipTap editor wrapper
RHFDatePicker @mui/x-date-pickers
RHFPhoneInput react-phone-number-input
RHFCountrySelect components/country-select

A typical form section:

const schema = z.object({ email: z.string().email(), password: z.string().min(8) });
const methods = useForm({ resolver: zodResolver(schema) });
return (
  <FormProvider {...methods}>
    <RHFTextField name="email" label="Email" />
    <RHFTextField name="password" label="Password" type="password" />
    <LoadingButton type="submit" loading={methods.formState.isSubmitting}>Sign in</LoadingButton>
  </FormProvider>
);

12. Theming

src/theme/index.ts creates the theme; src/theme/options/ contains palette / typography / overrides. Light & dark variants share tokens; the active mode is read from the Settings drawer.

  • Primary: Public Sans Variable (per cursor rules).
  • Secondary: Barlow.
  • Breakpoints: xs=600, sm=600, md=900, lg=1200, xl=1536.
  • Shape radius: 8 (default), customizable in settings.

See Theme Configuration and Design System Overview.


13. Settings drawer

src/settings/ provides a side-drawer that lets a user toggle:

  • Mode (light / dark / system)
  • Contrast (default / high)
  • Layout (vertical / mini / horizontal nav)
  • Direction (ltr / rtl)
  • Color preset (one of N curated palettes)
  • Font family override

State persists in localStorage under settings-key.

Note

The Telegram Mini App shell does not render the settings drawer; theme and direction are inherited from the parent app's stored settings at launch.


14. Editor (TipTap)

components/editor/ wraps @tiptap/react with these extensions enabled:

  • StarterKit (paragraph, headings, bold/italic, lists, blockquote)
  • Link (URL parsing)
  • Image (upload via components/upload)
  • Underline, TextAlign
  • CodeBlock + CodeBlockLowlight (syntax highlighting via lowlight)
  • Placeholder

Used in:

  • Blog post editor (dashboard/post/new, dashboard/post/[id]/edit)
  • Long-form description fields in Purchase Request & Request Template forms
  • Dispute evidence narrative

Content is stored as HTML in MongoDB. react-markdown + remark-gfm are available where Markdown rendering is preferred (e.g., chat messages).


15. File uploads

components/upload/ provides a dropzone with:

  • Multi-file selection
  • Drag-and-drop
  • Per-file progress
  • Preview (components/file-thumbnail/ shows by MIME)
  • Removal
  • Total-size enforcement (5 MB default, matches MAX_FILE_SIZE)

Backed by /api/file/* (multipart upload).


16. Sentry

@sentry/nextjs is initialised at app boot. Errors include user context (role, userId) and breadcrumbs (route changes, API failures). Source maps uploaded at build time.


17. Build & deploy

package.json:

  • devnext dev -p 8083 --turbopack
  • buildnext build && cp .next/static .next/standalone/.next/ && cp -r public .next/standalone/
  • startPORT=8083 node .next/standalone/server.js

Dockerfile is a 2-stage multi-stage build that produces .next/standalone/ and copies into a small node:22-alpine runner image with non-root user nextjs. Healthcheck via curl http://localhost:8083.

CI: .gitea/workflows/deploy.yml runs scripts/deploy.sh on push to main / master.

See Docker Setup, CI-CD Pipeline, and Deployment.


18. Notable files for orientation

File Why it matters
src/app/layout.tsx Provider tree
src/app/telegram/layout.tsx TMA shell — TonConnectUIProvider + slim provider tree
src/lib/axios.ts Every HTTP call goes through this
src/contexts/socket-context.tsx Realtime plumbing
src/theme/index.ts Theme creation entry
src/locales/locales-config.ts i18next setup
src/settings/context/ Settings context (persistence)
next.config.ts Standalone build, COOP/COEP headers for Web3 popups

19. Telegram Mini App (TMA) layer

Overview

The app ships a dedicated Telegram Mini App shell at app/telegram/. It is served from the same Next.js process and Docker image as the main web app; no separate deployment is required. The Telegram bot registers the Mini App URL pointing at /telegram.

Provider tree (TMA layout)

The TMA layout replaces the full dashboard shell with a minimal provider stack:

flowchart TB
    A[TelegramLayout]
    A --> B[AppRouterCacheProvider]
    B --> C[ThemeProvider]
    C --> D[QueryClientProvider]
    D --> E[SocketProvider]
    E --> F[TonConnectUIProvider<br/>manifestUrl: /tonconnect-manifest.json]
    F --> G[SnackbarProvider]
    G --> H[Children — telegram routes]

TonConnectUIProvider is the only addition relative to the web tree. Settings drawer, i18n provider, and auth guards are replaced by a Telegram initData token guard.

Routes and features

Route Description
telegram/shop Seller list with product browsing; infinite scroll
telegram/shop/[seller] Single seller's catalogue
telegram/cart In-shell shopping cart; checkout hands off to full web checkout URL
telegram/account Account tab with dashboard parity: profile, wallet, order history

Authentication flow

  1. Telegram injects window.Telegram.WebApp.initData on launch.
  2. The TMA guard sends initData to /api/auth/telegram for HMAC verification.
  3. On success the backend issues a short-lived JWT that the axios instance attaches as Bearer.
  4. Role-based access (seller vs buyer views) is honoured via the same guard mechanism used in the dashboard.

Real-time

SocketProvider is reused unchanged. The TMA shop, cart, and account tabs receive live socket updates (new messages, payment status, cart changes) on the same room infrastructure as the web dashboard.

TON Connect (Telegram Wallet)

Dependencies added: @ton/core, @tonconnect/ui-react.

TonConnectUIProvider wraps the TMA routes and exposes a useTonConnectUI() hook. The manifest at public/tonconnect-manifest.json declares the app identity to the TON Connect protocol.

Current status: the wallet connection UI is in place (connect / disconnect / show address). Actual TON payment processing is not yet wired to the backend — the provider is pre-positioned for a future TON payment rail on the escrow platform. When that rail is built, the checkout handoff in telegram/cart will be extended to emit a TON transaction instead of redirecting to the web checkout.

Constraints and differences from web

  • No settings drawer (theme follows web localStorage, defaults to light/ltr).
  • No TipTap editor or file-upload dropzone in TMA routes.
  • @mui/x-date-pickers and DataGrid are not loaded in the TMA bundle.
  • COOP/COEP headers required for WalletConnect popups are relaxed for TMA routes because Telegram's WebView does not support SharedArrayBuffer.