Welcome to the codebase! This document serves as the single source of truth for how the frontend is structured. It covers where files go, how data flows, and how we handle errors.
The frontend strictly separates what runs in the Browser vs what runs on the Node Server.
Files here do the heavy lifting of talking to microservices and reading secure cookies. The browser can never import anything from here.
- src/server/http/clients.ts: Configures the raw Axios instances pointing to NestJS microservices.
src/server/services/*.service.ts: The BFF (Backend-for-Frontend) abstraction layer. Formats outgoing requests and normalizes incoming errors.- src/server/bff/auth-guard.ts: Secures API Route Handlers by reading
HttpOnlytokens. src/server/jwt/verify.ts: Uses secrets from.envto verify tokens (Notice how we correctly moved this out ofsrc/lib/since it uses server secrets).
These act as the "controllers" for the Next.js server.
- They do not contain business logic.
- They extract JSON bodies or query params, call a
src/server/service/*, and return standard JSON. - They attach the
Set-Cookieheaders for auth.
We group UI code by feature, not by technical type. If you are building the "Chat" system, everything goes into src/features/chat:
features/chat/components/: React components specific to chat (ChatWindow,MessageBubble.tsx). Try to use Server Components where feasible, use'use client'when interactivity is required.features/chat/hooks/: Client-side data fetching or UI state logic (useChat.ts).features/chat/types/: TypeScript definitions (Message.interface.ts).
Libraries and configurations that both the Browser and the Server might need to safely import.
- src/lib/constants/error-codes.ts: The master list of error strings.
src/lib/redux/: Global client-side state management (Store, slices).- src/lib/errors/app-error.ts: Custom client-side error classes.
Small, pure functions. No side effects.
- Formatting dates, regex validators, math helpers.
- src/utils/service-error.ts: Simple error formatting class used by the
src/server/services/.
It is vital to understand the difference between backend API errors and frontend client errors.
If the microservice throws an error (e.g., "Invalid Password"):
- The microservice returns a
400 Bad Requestwith{ message: "...", errorCode: "INVALID_CREDENTIALS" }. - The src/server/services/auth.service.ts catches the Axios failure. It passes it to handleAxiosError().
- handleAxiosError() returns a strictly typed ServiceError object.
- The Route Handler (
src/app/api/auth/login/route.ts) sees the ServiceError and forwards itsmessageanderrorCodeas JSON to the browser. - The Redux Thunk throws the
messageusingrejectWithValue(data.message).
In the UI Hook or Component! The Redux Thunk's job is purely state. Do not put toast.error() inside a Redux slice.
// Inside features/auth/hooks/use-login.ts
const dispatch = useAppDispatch();
const handleLogin = async (credentials) => {
const resultAction = await dispatch(loginUser(credentials));
if (loginUser.fulfilled.match(resultAction)) {
toast.success('Welcome back!');
router.push('/dashboard');
} else {
// resultAction.payload contains the string message from the ServiceError!
toast.error(resultAction.payload || 'Login failed');
}
};If ServiceError handles all backend API problems, what is src/lib/errors/app-error.ts for? It is used for before-the-request or purely structural frontend errors.
Examples where a component or hook might throw an AppError:
- The user tries to upload an image, but it exceeds 5MB. You catch it before it even hits Redux and throw an AppError('File too large', 'VALIDATION_ERROR').
- Local UI state corruption or missing critical browser APIs (like LocalStorage failing).
- DON'T make an Axios call to
http://localhost:4000from the browser or Redux. The browser only calls Next.js/api/.... - DON'T manually manage
accessTokencookies on the client side.HttpOnlycookies are invisible to JavaScript. Let the browser send them automatically. - DO keep API Route Handlers (
route.ts) small. Delegate the work tosrc/server/services/. - DO use
toast.errorinside React components or standard React hooks, keep visual notifications out of Redux and Route handlers. - DO write Server Components whenever possible to fetch initial data directly from
src/server/services/without needing an/api/route at all!