Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:This document provides a comprehensive overview of the frontend architecture for the Eyewear Store Website. The project is a Next.js application built with TypeScript, designed to be modular, scalable, and maintainable. It follows a feature-based organization, separating concerns into distinct layers for UI, business logic, state management, and API communication.
The architecture emphasizes strong typing with Zod for validation, a clear separation between client and server state, and a robust API client capable of handling authentication and errors gracefully. The structure is intended to support both the customer-facing shop and a separate admin dashboard for managing products, users, and orders.
Core Technologies
The application is built on a modern web stack, leveraging the following key libraries and frameworks.
| Technology | Version | Purpose | Source |
|---|---|---|---|
| Next.js | 16.0.1 | React framework for routing, rendering, and server-side features. | package.json:44 |
| React | ^19 | UI library for building components. | package.json:45 |
| TypeScript | ^5.9.3 | Superset of JavaScript for static typing. | package.json:84 |
| Tailwind CSS | ^4.1.9 | Utility-first CSS framework for styling. | package.json:83 |
| shadcn/ui | N/A | Re-usable UI components built with Radix UI and Tailwind CSS. | package.json:16-39 |
| Zustand | ^5.0.8 | Minimalist global state management. | package.json:58 |
| TanStack Query | ^5.90.7 | Server state management (fetching, caching, updating). | package.json:40 |
| Axios | ^1.13.1 | Promise-based HTTP client for API communication. | package.json:42 |
| Zod | 3.25.76 | TypeScript-first schema declaration and validation. | package.json:57 |
| React Hook Form | ^7.60.0 | Form state management and validation. | package.json:47 |
| Playwright | ^1.56.1 | End-to-end testing framework. | package.json:65 |
| Jest | ^30.0.0 | JavaScript testing framework for unit/integration tests. | package.json:79 |
Sources: package.json
Project Structure
The repository is organized following a feature-based approach to promote modularity and separation of concerns. High-level directories are dedicated to specific responsibilities like routing, shared components, feature logic, and utilities.
Sources: README.md:14-41
This diagram shows the top-level directory structure of the project.
app/: Contains all routes, pages, and layouts, following the Next.js App Router conventions. It includes route groups for different application sections like(shop)and(account), as well as theadminsection.components/: Holds shared, reusable React components. This includes low-leveluicomponents (from shadcn/ui),layoutcomponents (header, footer), andskeletonsfor loading states.features/: The core of the feature-based architecture. Each subdirectory (e.g.,products,orders) is a self-contained module with its own components, hooks, services, and types.lib/: A library of shared utilities, helpers, and configurations. This includes the centralapi-client.ts, Zod validation schemas, and other utility functions.stores/: Contains global state management stores implemented with Zustand (e.g., for the cart and user session).types/: Defines shared TypeScript types and interfaces used across the application, such as API responses and data models.
Architectural Principles
The project adheres to several key principles to ensure a clean and scalable codebase.
Sources: README.md:43-69
Feature-based Organization
Each business feature (e.g., Products, Orders, Cart) is encapsulated within its own directory in features/. This modular structure reduces coupling and makes the codebase easier to navigate and maintain.
This diagram illustrates how a single feature module, like products, contains all its related logic, and how a page component consumes it.
Sources: README.md:46-51, app/admin/products/page.tsx
Service Layer
Business logic, particularly logic involving API communication and data transformation, is abstracted into a dedicated service layer. These services are typically classes or objects that provide methods for interacting with backend resources. This separates data-fetching logic from the UI components, making it reusable and easier to test.
The AdminProductsService is a prime example, handling all CRUD operations for products in the admin panel, including multipart form data for file uploads.
Sources: README.md:53-58, features/products/services/admin-products.service.ts
This class diagram shows the AdminProductsService implementing its interface and using the apiClient for HTTP requests.
Sources: features/products/services/admin-products.service.ts:21-197
State Management
The application employs a hybrid approach to state management, choosing the right tool for each type of state.
- Global State (Zustand): Used for state that needs to be shared across many components, such as the user's authentication status (
auth.store.ts) or the contents of the shopping cart (cart.store.ts). - Server State (TanStack Query): Although noted as a future plan in the README, its inclusion in
package.jsonand use in hooks likeuseAdminProductsindicates it is the chosen solution for managing asynchronous server state. It handles caching, re-fetching, and synchronization of data from the API. - Local Component State (React Hooks):
useStateanduseReducerare used for state that is local to a single component, such as form inputs or UI toggles.
Sources: README.md:60-64, package.json:40, app/admin/products/page.tsx:25
Type Safety
The project heavily relies on TypeScript to ensure type safety. Zod is used to define schemas for data structures, which provides both static TypeScript types and runtime validation. This is particularly important for validating API responses.
The types/ directory contains definitions for core data models like Product and ApiError, along with Zod schemas for validation. Preprocessing functions are used within Zod schemas to sanitize incoming data, such as converting date strings or handling nullish values.
Sources: README.md:66-70, types/common.types.ts, types/product.types.ts
API Communication
All communication with the backend is centralized through a pre-configured Axios instance located in lib/api-client.ts.
API Client Configuration
The client is configured with a base URL, timeout, and headers.
| Configuration | Value | Description |
|---|---|---|
BASE_URL | process.env.NEXT_PUBLIC_API_URL or http://localhost:3000 | The base URL for all API requests. |
TIMEOUT | 10000 | Default request timeout in milliseconds. |
RETRY_COUNT | 3 | Number of retries for failed requests (not yet implemented in interceptor). |
RETRY_DELAY | 1000 | Delay between retries in milliseconds (not yet implemented). |
Sources: lib/api-client.ts:18-23
Authentication and Token Refresh
The API client uses interceptors to manage authentication tokens automatically.
- Request Interceptor: Before any request is sent, the interceptor retrieves the
accessTokenfrom theauth.store(Zustand) and adds it to theAuthorizationheader. - Response Interceptor: If a request fails with a
401 Unauthorizedstatus, the interceptor attempts to refresh the token. It sends therefreshTokento the/auth/refreshendpoint. If successful, it updates the tokens in the store, updates the header of the original failed request, and retries it. If the refresh fails, the user's tokens are cleared, and they are redirected to the login page.
Sources: lib/api-client.ts:37-111
The following sequence diagram illustrates the token refresh flow.
Validated API Helpers
To enforce type safety, the client provides wrapper functions (e.g., apiGetValidated, apiPostValidated) that take a Zod schema as an argument. After receiving a response from the API, these functions parse the response data against the provided schema, throwing an error if the data does not match the expected shape.
Sources: lib/api-client.ts:184-245
Routing and Layouts
The application uses the Next.js App Router for file-system-based routing.
- Route Groups: Directories like
(shop)and(account)are used to organize routes without affecting the URL path, allowing for different layouts or logic for sections of the app. - Layouts: The
layout.tsxfile in a directory defines a shared UI for a segment of routes. For example,app/admin/layout.tsxwraps all admin pages with a common sidebar, header, and protected route logic. - Protected Routes: The
ProtectedRoutecomponent wraps layouts or pages that require authentication. Inapp/admin/layout.tsx, it ensures that only users with theADMINrole can access the admin dashboard.
Sources: README.md:15-17, app/admin/layout.tsx:1-93, app/layout.tsx
The diagram below shows how the admin layout is composed.
Testing
The project has a testing strategy that includes both end-to-end and unit/integration tests.
- End-to-End (E2E) Testing: Playwright is used for E2E testing. Test files are located in the
e2e/directory. The tests cover user flows like checkout (e2e/checkout-cod.spec.ts). Scripts inpackage.json(test:e2e,test:e2e:ui) are provided to run these tests. - Unit & Integration Testing: Jest and React Testing Library are set up for component and service testing. Test files (
.spec.tsor.spec.tsx) are co-located with the source files they test (e.g.,features/addresses/services/addresses.service.spec.ts). These tests mock dependencies like API clients to test business logic in isolation.
Sources: package.json:7-11, E2E_TESTING.md, features/addresses/services/addresses.service.spec.ts
Summary
The architecture of the frontend-luan-van project is well-defined and modern. It leverages the strengths of Next.js and the React ecosystem to create a scalable and maintainable application. Key strengths include its modular feature-based organization, a clear separation of concerns through a dedicated service layer, robust state management, and a resilient API client with automatic token handling. This structure provides a solid foundation for both current functionality and future development.