--- title: Frontend Architecture tags: [architecture, frontend, nextjs] created: 2026-05-23 --- # Frontend Architecture Module-level architecture of the Next.js 16 (App Router) + TypeScript + MUI v7 frontend at `/Users/mojtabaheidari/code/frontend` (development branch). > [!info] > Repo: `git@git.manko.yoga:222/nick/frontend.git` · Branch: `development` · Version: 1.9.6 (`package.json:4`) · 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) │ ├── 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|...) ├── components/ # Reusable UI primitives (hook-form, table, upload, editor, ...) ├── layouts/ # Page-template wrappers (auth-centered, auth-split, dashboard, main) ├── 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) ```mermaid flowchart TB A[RootLayout] A --> B[AppRouterCacheProvider
MUI emotion cache] B --> C[ThemeProvider
theme + RTL stylis] C --> D[LocalizationProvider
dayjs adapter] D --> E[I18nProvider
i18next] E --> F[QueryClientProvider
React Query] F --> G[SocketProvider
Socket.IO context] G --> H[SnackbarProvider
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). --- ## 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) | `AuthGuard` → `EmailVerificationGuard` | | `dashboard/user/*` | dashboard | + `role: admin` | | `dashboard/post/*` (editor) | dashboard | + `role: admin` | | `dashboard/shop-settings/*` | dashboard | + `role: seller` | Guards live in `frontend/src/auth/` (HOC + hook). They consult the JWT-derived user context and redirect unauthenticated to `/auth/jwt/sign-in?returnTo=...`. --- ## 5. Sections vs components vs hooks The codebase enforces a three-layer split: | Layer | Lives in | Purpose | Example | |---|---|---|---| | **Section** | `src/sections//` | Page-specific composition; orchestrates components | `sections/chat/view/ChatView.tsx` | | **Component** | `src/components//` | Reusable across sections | `components/hook-form/RHFTextField.tsx` | | **Hook** | `src/hooks/.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), `.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: `['', ]` 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: ```ts 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 | See [[Real-time Layer]] for the full event catalog. --- ## 9. Web3 integration ```ts // 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. --- ## 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//*.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: ```tsx const schema = z.object({ email: z.string().email(), password: z.string().min(8) }); const methods = useForm({ resolver: zodResolver(schema) }); return ( Sign in ); ``` --- ## 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`. --- ## 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`: - `dev` → `next dev -p 8083 --turbopack` - `build` → `next build && cp .next/static .next/standalone/.next/ && cp -r public .next/standalone/` - `start` → `PORT=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/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 | --- ## Related - [[System Architecture]] — bird's-eye topology - [[Backend Architecture]] — server peer - [[Real-time Layer]] — Socket.IO plumbing - [[Design System Overview]] · [[Theme Configuration]] · [[Components]] - [[Tech Stack]] — versions - [[Coding Standards]] — UI cursor-rules summary