14 KiB
title, tags, created
| title | tags | created | |||
|---|---|---|---|---|---|
| Frontend Architecture |
|
2026-05-23 |
Frontend Architecture
Module-level architecture of the Next.js 16 (App Router) + TypeScript + MUI v7 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.7.19 (package.json) · Dev port3000, Docker port8083.
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'innext.config.tsfor 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.tsxand Suspense boundaries. - MUI cache is wired up via
@mui/material-nextjsin 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).
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/<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 hasindex.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
QueryClientcreated once at the root layout withdefaultOptions: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:
- Opens the connection after authentication (token from storage).
- Auto-joins user-specific rooms (
user-{id},seller-{id}orbuyer-{id}based on role). - Exposes a
useSocket()hook returningsocket,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
// 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-i18nextinitialized insrc/locales/locales-config.tswith 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-rtlis wired into the MUI cache whendir === 'rtl'. - Date formatting via
dayjswith locale auto-loaded. - Number formatting via
Intl.NumberFormat+ helper atlocales/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.
14. Editor (TipTap)
components/editor/ wraps @tiptap/react with these extensions enabled:
StarterKit(paragraph, headings, bold/italic, lists, blockquote)Link(URL parsing)Image(upload viacomponents/upload)Underline,TextAlignCodeBlock+CodeBlockLowlight(syntax highlighting vialowlight)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 --turbopackbuild→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