Compare commits

..

3 Commits

  1. 198
      README.md
  2. 2
      src/app.module.ts
  3. 1
      src/core/constants/index.ts
  4. 3
      src/core/database/database.providers.ts
  5. 6
      src/modules/orders/orders.controller.ts
  6. 11
      src/modules/orders/orders.service.ts
  7. 13
      src/modules/users/entities/user.entity.ts
  8. 3
      src/modules/wallets/dto/update-wallet.dto.ts
  9. 26
      src/modules/wallets/entities/wallet.entity.ts
  10. 24
      src/modules/wallets/wallets.controller.ts
  11. 11
      src/modules/wallets/wallets.module.ts
  12. 9
      src/modules/wallets/wallets.providers.ts
  13. 45
      src/modules/wallets/wallets.service.ts

@ -1,99 +1,151 @@
<p align="center">
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Project setup
# CRUD
```bash
$ npm install
```
# Backend API for E-commerce Application
## Compile and run the project
This is a simple **Backend Service API** for a **E-commerce Application** with various endpoints built using **Nest.js**, **PostgreSQL** & **Sequelize**.
```bash
# development
$ npm run start
---
# watch mode
$ npm run start:dev
## Features
# production mode
$ npm run start:prod
```
- Built with **Nest.js**.
- **PostgreSQL** and **Sequelize** for database management.
- Implements **JWT Authentication**.
- RESTful APIs for user management:
- Create, Read, Update, and Delete (CRUD) operations.
## Run tests
---
```bash
# unit tests
$ npm run test
## Technologies Used
# e2e tests
$ npm run test:e2e
- **Nest.js**
- **PostgreSQL** with **Sequelize**
- **JWT** for authentication
- **ARGON2** for password hashing
# test coverage
$ npm run test:cov
```
---
## Deployment
## Installation and Setup
When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
### Prerequisites
If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
- Node.js and npm installed on your system.
- postgreSQL connection (local or cloud).
### 1. Clone the Repository
```bash
$ npm install -g mau
$ mau deploy
git clone https://github.com/MahdiTajikKazemi/e-commerce-api-nestjs-postgres-sequelize
```
With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
### 2. Setup Backend
## Resources
1. Install dependencies:
```bash
npm install
```
2. Create a `.env` file in the `backend` directory and configure it:
```env
Set your environment variables in .env.sample file.
```
3. Start the server:
```bash
npm run start:dev
```
Check out a few resources that may come in handy when working with NestJS:
## Usage
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
1. Start the backend server.
2. Open your 'Postman' | 'insomnia' or whatever testing api app you are comfortable using and then begin hitting enpoints listed below.
## Support
---
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## API Endpoints
## Stay in touch
### Authentication
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
- `POST /api/v1/auth/signup`: Register a new user and get a JWT token.
- `POST /api/v1/auth/login`: Login and get a JWT token.
### User Management
- `GET /api/v1/users/`: Get a list of all users (admin only).
- `POST /api/v1/users/`: Create a user (admin only).
- `PATCH /api/v1/users/:id`: Update a specific user (admin only).
- `DELETE /api/v1/users/:id`: Remove a specific user (admin only).
- `GET /api/v1/users/:id`: Get a specific user (admin only).
---
## Folder Structure
```
└── 📁src
└── 📁core
└── 📁constants
└── index.ts
└── 📁database
└── database.config.ts
└── database.module.ts
└── database.providers.ts
└── 📁interfaces
└── dbConfig.interface.ts
└── 📁modules
└── 📁auth
└── auth.controller.ts
└── auth.module.ts
└── auth.service.ts
└── jwt.strategy.ts
└── local.strategy.ts
└── 📁orders
└── 📁dto
└── create-order.dto.ts
└── index.ts
└── update-order.dto.ts
└── 📁entities
└── order-status.entity.ts
└── order.entity.ts
└── order-statuses.providers.ts
└── orders.controller.ts
└── orders.module.ts
└── orders.providers.ts
└── orders.service.ts
└── 📁products
└── 📁dto
└── create-product.dto.ts
└── index.ts
└── update-product.dto.ts
└── 📁entities
└── product.entity.ts
└── products.controller.ts
└── products.module.ts
└── products.providers.ts
└── products.service.ts
└── 📁users
└── 📁dto
└── create-user.dto.ts
└── index.ts
└── update-user.dto.ts
└── 📁entities
└── user.entity.ts
└── users.controller.ts
└── users.module.ts
└── users.providers.ts
└── users.service.ts
└── app.controller.ts
└── app.module.ts
└── app.service.ts
└── main.ts
```
## Future Enhancements
- Integrate redis for cashing
---
## License
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
This project is licensed under the MIT License.
Mahdi Tajik Kazemi

@ -8,6 +8,7 @@ import { UsersController } from './modules/users/users.controller';
import { ProductsModule } from './modules/products/products.module';
import { AuthModule } from './modules/auth/auth.module';
import { OrdersModule } from './modules/orders/orders.module';
import { WalletsModule } from './modules/wallets/wallets.module';
@Module({
imports: [
@ -17,6 +18,7 @@ import { OrdersModule } from './modules/orders/orders.module';
ProductsModule,
AuthModule,
OrdersModule,
WalletsModule,
],
controllers: [AppController, UsersController],
providers: [AppService],

@ -6,3 +6,4 @@ export const USER_REPOSITORY = 'USER_REPOSITORY';
export const PRODUCT_REPOSITORY = 'PRODUCT_REPOSITORY';
export const ORDER_REPOSITORY = 'ORDER_REPOSITORY';
export const ORDER_STATUSES_REPOSITORY = 'ORDER_STATUSES_REPOSITORY';
export const WALLET_REPOSITORY = 'WALLET_REPOSITORY';

@ -5,6 +5,7 @@ import { User } from 'src/modules/users/entities/user.entity';
import { Product } from 'src/modules/products/entities/product.entity';
import { OrderStatuses } from 'src/modules/orders/entities/order-status.entity';
import { Order } from 'src/modules/orders/entities/order.entity';
import { Wallet } from 'src/modules/wallets/entities/wallet.entity';
export const databaseProviders = [
{
@ -25,7 +26,7 @@ export const databaseProviders = [
config = databaseConfig.development;
}
const sequelize = new Sequelize(config);
sequelize.addModels([User, Product, Order, OrderStatuses]);
sequelize.addModels([User, Product, Order, OrderStatuses, Wallet]);
await sequelize.sync();
return sequelize;
},

@ -10,6 +10,7 @@ import {
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create-order.dto';
import { UpdateOrderDto } from './dto/update-order.dto';
import { UUID } from 'crypto';
@Controller('orders')
export class OrdersController {
@ -25,6 +26,11 @@ export class OrdersController {
return this.ordersService.findAll();
}
@Get('users/:id')
findByUser(@Param('id') id: UUID) {
return this.ordersService.findByUser(id);
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.ordersService.findOne(+id);

@ -4,6 +4,7 @@ import { Order } from './entities/order.entity';
import { ORDER_REPOSITORY } from 'src/core/constants';
import { OrderStatuses } from './entities/order-status.entity';
import { User } from '../users/entities/user.entity';
import { UUID } from 'crypto';
@Injectable()
export class OrdersService {
@ -30,6 +31,16 @@ export class OrdersService {
});
}
async findByUser(id: UUID) {
return await this.orderRepository.findAll({
include: {
model: User,
where: { uuid: id },
attributes: ['firstName', 'lastName'],
},
});
}
async update(id: number, updateOrderDto: UpdateOrderDto) {
const [numberOfAffectedRows, [updatedOrder]] =
await this.orderRepository.update(

@ -1,5 +1,13 @@
import { Table, Column, Model, DataType, HasMany } from 'sequelize-typescript';
import {
Table,
Column,
Model,
DataType,
HasMany,
HasOne,
} from 'sequelize-typescript';
import { Order } from '../../orders/entities/order.entity';
import { Wallet } from 'src/modules/wallets/entities/wallet.entity';
@Table({ tableName: 'users' })
export class User extends Model<User> {
@ -56,4 +64,7 @@ export class User extends Model<User> {
@HasMany(() => Order)
orders: Order[];
@HasOne(() => Wallet)
wallet: Wallet;
}

@ -0,0 +1,3 @@
export class UpdateWalletDto {
amount: number;
}

@ -0,0 +1,26 @@
import {
Table,
Column,
Model,
DataType,
ForeignKey,
BelongsTo,
} from 'sequelize-typescript';
import { User } from 'src/modules/users/entities/user.entity';
@Table({ tableName: 'wallets', createdAt: false })
export class Wallet extends Model<Wallet> {
@Column({
type: DataType.FLOAT,
allowNull: false,
defaultValue: 0,
})
balance: number;
@ForeignKey(() => User)
@Column
userId: number;
@BelongsTo(() => User)
user: User;
}

@ -0,0 +1,24 @@
import { Body, Controller, Get, Param, Patch } from '@nestjs/common';
import { WalletsService } from './wallets.service';
import { UUID } from 'crypto';
import { UpdateWalletDto } from './dto/update-wallet.dto';
@Controller('wallets')
export class WalletsController {
constructor(private readonly walletsService: WalletsService) {}
@Get('balance/:id')
getWallet(@Param('id') id: UUID) {
return this.walletsService.getWallet(id);
}
@Patch('deposit/:id')
deposit(@Param('id') id: UUID, @Body() updateWalletDto: UpdateWalletDto) {
return this.walletsService.deposit(id, updateWalletDto);
}
@Patch('withdraw/:id')
withdraw(@Param('id') id: UUID, @Body() updateWalletDto: UpdateWalletDto) {
return this.walletsService.withdraw(id, updateWalletDto);
}
}

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { WalletsService } from './wallets.service';
import { WalletsController } from './wallets.controller';
import { walletsProviders } from './wallets.providers';
@Module({
controllers: [WalletsController],
providers: [WalletsService, ...walletsProviders],
exports: [WalletsService],
})
export class WalletsModule {}

@ -0,0 +1,9 @@
import { Wallet } from './entities/wallet.entity';
import { WALLET_REPOSITORY } from '../../core/constants';
export const walletsProviders = [
{
provide: WALLET_REPOSITORY,
useValue: Wallet,
},
];

@ -0,0 +1,45 @@
import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { UUID } from 'crypto';
import { WALLET_REPOSITORY } from 'src/core/constants';
import { Wallet } from './entities/wallet.entity';
import { User } from '../users/entities/user.entity';
import { UpdateWalletDto } from './dto/update-wallet.dto';
@Injectable()
export class WalletsService {
constructor(
@Inject(WALLET_REPOSITORY) private readonly walletRepository: typeof Wallet,
) {}
async getWallet(id: UUID) {
return await this.walletRepository.findAll({
include: {
model: User,
where: { uuid: id },
attributes: ['firstName'],
},
});
}
async deposit(id: UUID, updateWalletDto: UpdateWalletDto) {
const { amount } = updateWalletDto;
if (amount < 0) throw new BadRequestException();
const [wallet] = await this.getWallet(id);
wallet.balance += amount;
return wallet.save();
}
async withdraw(id: UUID, updateWalletDto: UpdateWalletDto) {
const { amount } = updateWalletDto;
if (amount < 0) throw new BadRequestException();
const [wallet] = await this.getWallet(id);
wallet.balance -= amount;
return wallet.save();
}
}
Loading…
Cancel
Save