A full-stack application with a NestJS backend and React frontend for user authentication. The project is fully containerized with Docker for both development and production environments.
This project is fully containerized. To run the application in a development environment:
# This will build and start the backend, frontend, and database containers.
# The frontend will be available at http://localhost:5173
# The backend will be available at http://localhost:3000
$ docker-compose up --buildTo run the application in a production environment:
$ docker-compose -f docker-compose.prod.yml up --buildThe backend is built with NestJS, a progressive Node.js framework for building efficient and scalable server-side applications.
- Database: MongoDB is used as the database, with Mongoose as the ODM for modeling application data.
- Architecture: The code follows a modular structure (
AuthModule,UsersModule) and utilizes the Repository Pattern (UsersRepository) to decouple the business logic from the data access layer. - Authentication: Implements a stateless authentication system using JWT (JSON Web Tokens) with an access token/refresh token strategy. Passwords are securely hashed using Argon2.
- Configuration: Environment variables are managed by the
@nestjs/configmodule and validated against a Joi schema. - Logging: Uses
nest-winstonfor structured, production-ready logging.
The frontend is a single-page application built with React and Vite.
- UI Framework: Ant Design is used for UI components, providing a robust set of high-quality components.
- State Management: Global state, specifically the authenticated user's session, is managed via React Context. Asynchronous state and server-side cache are handled by TanStack Query (React Query), which simplifies data fetching, caching, and synchronization.
- Routing: React Router is used for all client-side routing, including protected routes that require authentication.
- Code Structure: Logic is encapsulated in custom hooks (e.g.,
useLogin,useSignUp) for clean, reusable, and maintainable components.
To ensure type safety between the frontend and backend, this project uses Orval. Orval generates a type-safe client on the frontend based on the backend's OpenAPI (Swagger) specification.
- The NestJS backend automatically generates a
swagger.yamlfile at/api/v1/swagger.yaml. This file describes all API endpoints, request bodies, and response shapes. - On the frontend, the
orvalcommand is run (or can be run vianpm run generate:api). - Orval reads the swagger endpoint and generates a fully typed React Query client located at
frontend/src/api/api.ts. - This generated client includes custom hooks for every API endpoint (e.g.,
useAuthControllerSignInV1,useAuthControllerMeV1). The directories are named after the swagger tags. - The frontend application imports and uses these generated hooks, providing compile-time type safety for all API interactions. If the backend API changes, running the Orval command will update the client, and any breaking changes will be caught by the TypeScript compiler on the frontend.
Warning The
frontend/src/apidirectory is entirely auto-generated by Orval. Do not edit any files in this directory manually, as your changes will be overwritten the next time the API client is generated.
The API is versioned, with the base path for version 1 being /api/v1. Full, interactive Swagger documentation is available at /api/v1/swagger when the application is running.
- Endpoint:
POST /auth/signup - Description: Registers a new user.
- Request Body:
{ "username": "testuser", "password": "Password123!" } - Success Response (201):
{ "accessToken": "...", "refreshToken": "...", "user": { "username": "testuser", "_id": "..." } }
- Endpoint:
POST /auth/signin - Description: Authenticates a user and returns JWT tokens.
- Request Body:
{ "username": "testuser", "password": "Password123!" } - Success Response (200):
{ "accessToken": "...", "refreshToken": "...", "user": { "username": "testuser", "_id": "..." } }
- Endpoint:
POST /auth/refresh - Description: Generates a new access token using a valid refresh token.
- Request Body:
{ "refreshToken": "..." } - Success Response (200):
{ "accessToken": "..." }
- Endpoint:
GET /auth/me - Authentication:
JWT Tokenrequired. This endpoint is protected. - Description: Retrieves the profile of the currently authenticated user.
- Success Response (200):
{ "username": "testuser", "_id": "..." }
- JWT Payload Security: To prevent leaking personally identifiable information (PII) if a token were ever compromised, the JWT payload contains only the non-sequential user
_id(subclaim) and not the email - Exposing
_id: In the current implementation, the user object returned by the API includes the MongoDB_idfield. In a production environment, it is best practice to not expose raw database identifiers. This should be mapped to a different, non-sequential public ID or removed from the public-facing DTO. - API Throttling: The API does not currently have rate-limiting implemented. To protect against brute-force attacks and denial-of-service, a throttler (like the one provided by
@nestjs/throttler) should be configured globally.