Repository: thevladbog/cider-code-backend
Pull request #4: feat: Add user controller
Author: login: thevladbog
Labels: name: enhancement
description: New feature or request
name: released on @release-beta
name: released on @release-stable
Created: 2025-04-26T22:45:04Z | Merged: 2025-04-26T23:27:06Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced user management endpoints for creating, retrieving, updating, and deleting user accounts with pagination support.
  - Added secure password handling with hashing for user data.
  - Added paginated product listing with page and limit query parameters.
- **Improvements**
  - Updated API documentation and application references to reflect the new project name and branding.
- **Database Changes**
  - Modified the user data model and database schema to replace hashed password storage with a simplified password field.
- **Chores**
  - Updated dependencies and project naming for consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/package-lock.json b/package-lock.json
index e4b48d6..e9d134f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
 {
-  "name": "cider-code-backend",
+  "name": "bottle-code-backend",
   "version": "0.0.1",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
-      "name": "cider-code-backend",
+      "name": "bottle-code-backend",
       "version": "0.0.1",
       "license": "UNLICENSED",
       "dependencies": {
@@ -15,6 +15,7 @@
         "@nestjs/platform-express": "^11.0.1",
         "@prisma/client": "^6.6.0",
         "@scalar/nestjs-api-reference": "^0.4.7",
+        "argon2": "^0.43.0",
         "nestjs-prisma": "^0.25.0",
         "nestjs-zod": "^4.3.1",
         "reflect-metadata": "^0.2.2",
@@ -3164,6 +3165,15 @@
         "npm": ">=5.10.0"
       }
     },
+    "node_modules/@phc/format": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@phc/format/-/format-1.0.0.tgz",
+      "integrity": "sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@pkgr/core": {
       "version": "0.2.3",
       "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.3.tgz",
@@ -5546,6 +5556,30 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/argon2": {
+      "version": "0.43.0",
+      "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.43.0.tgz",
+      "integrity": "sha512-u/HKLcbWShVDhkfwI4hWyiUf3qyX8QhTfaIv2cWE18uqhXCmR5hb6Ed7oqYi2KCQegeAnRhiFzbjzm7i5yl1GA==",
+      "hasInstallScript": true,
+      "license": "MIT",
+      "dependencies": {
+        "@phc/format": "^1.0.0",
+        "node-addon-api": "^8.3.1",
+        "node-gyp-build": "^4.8.4"
+      },
+      "engines": {
+        "node": ">=16.17.0"
+      }
+    },
+    "node_modules/argon2/node_modules/node-addon-api": {
+      "version": "8.3.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
+      "integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
+      "license": "MIT",
+      "engines": {
+        "node": "^18 || ^20 || >= 21"
+      }
+    },
     "node_modules/argparse": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -10104,6 +10138,17 @@
         "lodash": "^4.17.21"
       }
     },
+    "node_modules/node-gyp-build": {
+      "version": "4.8.4",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+      "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+      "license": "MIT",
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
     "node_modules/node-int64": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
diff --git a/package.json b/package.json
index eba7bdf..f9a9ce1 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
 {
-  "name": "cider-code-backend",
+  "name": "bottle-code-backend",
   "version": "0.0.1",
   "description": "",
   "author": "Vladislav Bogatyrev",
@@ -32,6 +32,7 @@
     "@nestjs/platform-express": "^11.0.1",
     "@prisma/client": "^6.6.0",
     "@scalar/nestjs-api-reference": "^0.4.7",
+    "argon2": "^0.43.0",
     "nestjs-prisma": "^0.25.0",
     "nestjs-zod": "^4.3.1",
     "reflect-metadata": "^0.2.2",
@@ -88,4 +89,4 @@
   "prisma": {
     "seed": "ts-node prisma/seed.ts"
   }
-}
+}
\ No newline at end of file
diff --git a/prisma/generated/zod/index.ts b/prisma/generated/zod/index.ts
index dddf02c..c7fc2c5 100644
--- a/prisma/generated/zod/index.ts
+++ b/prisma/generated/zod/index.ts
@@ -43,7 +43,7 @@ export const ShiftScalarFieldEnumSchema = z.enum(['id','plannedDate','productId'
 
 export const OperatorScalarFieldEnumSchema = z.enum(['id','name','barcode','created','modified']);
 
-export const UserScalarFieldEnumSchema = z.enum(['id','email','firstName','lastName','hashedPassword','created','modified']);
+export const UserScalarFieldEnumSchema = z.enum(['id','email','firstName','lastName','password','created','modified']);
 
 export const SortOrderSchema = z.enum(['asc','desc']);
 
@@ -168,7 +168,7 @@ export const UserSchema = z.object({
   email: z.string(),
   firstName: z.string(),
   lastName: z.string(),
-  hashedPassword: z.string(),
+  password: z.string(),
   created: z.coerce.date(),
   modified: z.coerce.date().nullable(),
 })
@@ -371,7 +371,7 @@ export const UserSelectSchema: z.ZodType<Prisma.UserSelect> = z.object({
   email: z.boolean().optional(),
   firstName: z.boolean().optional(),
   lastName: z.boolean().optional(),
-  hashedPassword: z.boolean().optional(),
+  password: z.boolean().optional(),
   created: z.boolean().optional(),
   modified: z.boolean().optional(),
 }).strict()
@@ -832,7 +832,7 @@ export const UserWhereInputSchema: z.ZodType<Prisma.UserWhereInput> = z.object({
   email: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
   firstName: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
   lastName: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
-  hashedPassword: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
+  password: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
   created: z.union([ z.lazy(() => DateTimeFilterSchema),z.coerce.date() ]).optional(),
   modified: z.union([ z.lazy(() => DateTimeNullableFilterSchema),z.coerce.date() ]).optional().nullable(),
 }).strict();
@@ -842,7 +842,7 @@ export const UserOrderByWithRelationInputSchema: z.ZodType<Prisma.UserOrderByWit
   email: z.lazy(() => SortOrderSchema).optional(),
   firstName: z.lazy(() => SortOrderSchema).optional(),
   lastName: z.lazy(() => SortOrderSchema).optional(),
-  hashedPassword: z.lazy(() => SortOrderSchema).optional(),
+  password: z.lazy(() => SortOrderSchema).optional(),
   created: z.lazy(() => SortOrderSchema).optional(),
   modified: z.union([ z.lazy(() => SortOrderSchema),z.lazy(() => SortOrderInputSchema) ]).optional(),
 }).strict();
@@ -867,7 +867,7 @@ export const UserWhereUniqueInputSchema: z.ZodType<Prisma.UserWhereUniqueInput>
   NOT: z.union([ z.lazy(() => UserWhereInputSchema),z.lazy(() => UserWhereInputSchema).array() ]).optional(),
   firstName: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
   lastName: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
-  hashedPassword: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
+  password: z.union([ z.lazy(() => StringFilterSchema),z.string() ]).optional(),
   created: z.union([ z.lazy(() => DateTimeFilterSchema),z.coerce.date() ]).optional(),
   modified: z.union([ z.lazy(() => DateTimeNullableFilterSchema),z.coerce.date() ]).optional().nullable(),
 }).strict());
@@ -877,7 +877,7 @@ export const UserOrderByWithAggregationInputSchema: z.ZodType<Prisma.UserOrderBy
   email: z.lazy(() => SortOrderSchema).optional(),
   firstName: z.lazy(() => SortOrderSchema).optional(),
   lastName: z.lazy(() => SortOrderSchema).optional(),
-  hashedPassword: z.lazy(() => SortOrderSchema).optional(),
+  password: z.lazy(() => SortOrderSchema).optional(),
   created: z.lazy(() => SortOrderSchema).optional(),
   modified: z.union([ z.lazy(() => SortOrderSchema),z.lazy(() => SortOrderInputSchema) ]).optional(),
   _count: z.lazy(() => UserCountOrderByAggregateInputSchema).optional(),
@@ -893,7 +893,7 @@ export const UserScalarWhereWithAggregatesInputSchema: z.ZodType<Prisma.UserScal
   email: z.union([ z.lazy(() => StringWithAggregatesFilterSchema),z.string() ]).optional(),
   firstName: z.union([ z.lazy(() => StringWithAggregatesFilterSchema),z.string() ]).optional(),
   lastName: z.union([ z.lazy(() => StringWithAggregatesFilterSchema),z.string() ]).optional(),
-  hashedPassword: z.union([ z.lazy(() => StringWithAggregatesFilterSchema),z.string() ]).optional(),
+  password: z.union([ z.lazy(() => StringWithAggregatesFilterSchema),z.string() ]).optional(),
   created: z.union([ z.lazy(() => DateTimeWithAggregatesFilterSchema),z.coerce.date() ]).optional(),
   modified: z.union([ z.lazy(() => DateTimeNullableWithAggregatesFilterSchema),z.coerce.date() ]).optional().nullable(),
 }).strict();
@@ -1324,7 +1324,7 @@ export const UserCreateInputSchema: z.ZodType<Prisma.UserCreateInput> = z.object
   email: z.string(),
   firstName: z.string(),
   lastName: z.string(),
-  hashedPassword: z.string(),
+  password: z.string(),
   created: z.coerce.date().optional(),
   modified: z.coerce.date().optional().nullable()
 }).strict();
@@ -1334,7 +1334,7 @@ export const UserUncheckedCreateInputSchema: z.ZodType<Prisma.UserUncheckedCreat
   email: z.string(),
   firstName: z.string(),
   lastName: z.string(),
-  hashedPassword: z.string(),
+  password: z.string(),
   created: z.coerce.date().optional(),
   modified: z.coerce.date().optional().nullable()
 }).strict();
@@ -1344,7 +1344,7 @@ export const UserUpdateInputSchema: z.ZodType<Prisma.UserUpdateInput> = z.object
   email: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   firstName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   lastName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
-  hashedPassword: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
+  password: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   created: z.union([ z.coerce.date(),z.lazy(() => DateTimeFieldUpdateOperationsInputSchema) ]).optional(),
   modified: z.union([ z.coerce.date(),z.lazy(() => NullableDateTimeFieldUpdateOperationsInputSchema) ]).optional().nullable(),
 }).strict();
@@ -1354,7 +1354,7 @@ export const UserUncheckedUpdateInputSchema: z.ZodType<Prisma.UserUncheckedUpdat
   email: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   firstName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   lastName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
-  hashedPassword: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
+  password: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   created: z.union([ z.coerce.date(),z.lazy(() => DateTimeFieldUpdateOperationsInputSchema) ]).optional(),
   modified: z.union([ z.coerce.date(),z.lazy(() => NullableDateTimeFieldUpdateOperationsInputSchema) ]).optional().nullable(),
 }).strict();
@@ -1364,7 +1364,7 @@ export const UserCreateManyInputSchema: z.ZodType<Prisma.UserCreateManyInput> =
   email: z.string(),
   firstName: z.string(),
   lastName: z.string(),
-  hashedPassword: z.string(),
+  password: z.string(),
   created: z.coerce.date().optional(),
   modified: z.coerce.date().optional().nullable()
 }).strict();
@@ -1374,7 +1374,7 @@ export const UserUpdateManyMutationInputSchema: z.ZodType<Prisma.UserUpdateManyM
   email: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   firstName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   lastName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
-  hashedPassword: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
+  password: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   created: z.union([ z.coerce.date(),z.lazy(() => DateTimeFieldUpdateOperationsInputSchema) ]).optional(),
   modified: z.union([ z.coerce.date(),z.lazy(() => NullableDateTimeFieldUpdateOperationsInputSchema) ]).optional().nullable(),
 }).strict();
@@ -1384,7 +1384,7 @@ export const UserUncheckedUpdateManyInputSchema: z.ZodType<Prisma.UserUncheckedU
   email: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   firstName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   lastName: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
-  hashedPassword: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
+  password: z.union([ z.string(),z.lazy(() => StringFieldUpdateOperationsInputSchema) ]).optional(),
   created: z.union([ z.coerce.date(),z.lazy(() => DateTimeFieldUpdateOperationsInputSchema) ]).optional(),
   modified: z.union([ z.coerce.date(),z.lazy(() => NullableDateTimeFieldUpdateOperationsInputSchema) ]).optional().nullable(),
 }).strict();
@@ -1931,7 +1931,7 @@ export const UserCountOrderByAggregateInputSchema: z.ZodType<Prisma.UserCountOrd
   email: z.lazy(() => SortOrderSchema).optional(),
   firstName: z.lazy(() => SortOrderSchema).optional(),
   lastName: z.lazy(() => SortOrderSchema).optional(),
-  hashedPassword: z.lazy(() => SortOrderSchema).optional(),
+  password: z.lazy(() => SortOrderSchema).optional(),
   created: z.lazy(() => SortOrderSchema).optional(),
   modified: z.lazy(() => SortOrderSchema).optional()
 }).strict();
@@ -1941,7 +1941,7 @@ export const UserMaxOrderByAggregateInputSchema: z.ZodType<Prisma.UserMaxOrderBy
   email: z.lazy(() => SortOrderSchema).optional(),
   firstName: z.lazy(() => SortOrderSchema).optional(),
   lastName: z.lazy(() => SortOrderSchema).optional(),
-  hashedPassword: z.lazy(() => SortOrderSchema).optional(),
+  password: z.lazy(() => SortOrderSchema).optional(),
   created: z.lazy(() => SortOrderSchema).optional(),
   modified: z.lazy(() => SortOrderSchema).optional()
 }).strict();
@@ -1951,7 +1951,7 @@ export const UserMinOrderByAggregateInputSchema: z.ZodType<Prisma.UserMinOrderBy
   email: z.lazy(() => SortOrderSchema).optional(),
   firstName: z.lazy(() => SortOrderSchema).optional(),
   lastName: z.lazy(() => SortOrderSchema).optional(),
-  hashedPassword: z.lazy(() => SortOrderSchema).optional(),
+  password: z.lazy(() => SortOrderSchema).optional(),
   created: z.lazy(() => SortOrderSchema).optional(),
   modified: z.lazy(() => SortOrderSchema).optional()
 }).strict();
diff --git a/prisma/migrations/20250426220749_change_password_field/migration.sql b/prisma/migrations/20250426220749_change_password_field/migration.sql
new file mode 100644
index 0000000..ab49c90
--- /dev/null
+++ b/prisma/migrations/20250426220749_change_password_field/migration.sql
@@ -0,0 +1,10 @@
+/*
+  Warnings:
+
+  - You are about to drop the column `hashedPassword` on the `User` table. All the data in the column will be lost.
+  - Added the required column `password` to the `User` table without a default value. This is not possible if the table is not empty.
+
+*/
+-- AlterTable
+ALTER TABLE "User" DROP COLUMN "hashedPassword",
+ADD COLUMN     "password" TEXT NOT NULL;
diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml
index 648c57f..044d57c 100644
--- a/prisma/migrations/migration_lock.toml
+++ b/prisma/migrations/migration_lock.toml
@@ -1,3 +1,3 @@
 # Please do not edit this file manually
 # It should be added in your version-control system (e.g., Git)
-provider = "postgresql"
\ No newline at end of file
+provider = "postgresql"
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d12612f..68a94ea 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -101,11 +101,11 @@ model Operator {
 }
 
 model User {
-  id             String @id @unique() @default(nanoid())
-  email          String @unique @db.VarChar(80)
-  firstName      String @map("first_name") @db.VarChar(80)
-  lastName       String @map("last_name") @db.VarChar(80)
-  hashedPassword String
+  id        String @id @unique() @default(nanoid())
+  email     String @unique @db.VarChar(80)
+  firstName String @map("first_name") @db.VarChar(80)
+  lastName  String @map("last_name") @db.VarChar(80)
+  password  String
 
   created  DateTime  @default(now()) @map("created_at")
   modified DateTime? @updatedAt @map("updated_at")
diff --git a/src/app.module.ts b/src/app.module.ts
index 420a445..cd0898c 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -9,6 +9,7 @@ import {
 } from 'nestjs-prisma';
 import { ConfigModule } from '@nestjs/config';
 import { ProductModule } from './product/product.module';
+import { UserModule } from './user/user.module';
 
 @Module({
   imports: [
@@ -19,6 +20,7 @@ import { ProductModule } from './product/product.module';
       isGlobal: true,
     }),
     ProductModule,
+    UserModule,
   ],
   controllers: [],
   providers: [
diff --git a/src/main.ts b/src/main.ts
index f41fc6c..bdd2c2d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,9 +1,9 @@
 import { NestFactory } from '@nestjs/core';
-import { AppModule } from './app.module';
 import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
 import { patchNestJsSwagger } from 'nestjs-zod';
 import { PrismaService } from 'nestjs-prisma';
 import { apiReference } from '@scalar/nestjs-api-reference';
+import { AppModule } from './app.module';
 
 patchNestJsSwagger();
 
@@ -12,10 +12,9 @@ async function bootstrap() {
   patchNestJsSwagger();
 
   const config = new DocumentBuilder()
-    .setTitle('CIDER [CODE] Backend')
-    .setDescription('The Cider Code API description')
+    .setTitle('BOTTLE [CODE] Backend')
+    .setDescription('The Bottle Code API description')
     .setVersion('1.0')
-    .addTag('cider')
     .build();
 
   const document = SwaggerModule.createDocument(app, config); // serializable object - conform to OpenAPI
@@ -31,8 +30,8 @@ async function bootstrap() {
       spec: {
         content: document,
       },
-      title: 'CIDER [CODE] Backend API',
-      slug: 'cider-code',
+      title: 'BOTTLE [CODE] Backend API',
+      slug: 'bottle-code',
       _integration: 'nestjs',
     }),
   );
@@ -47,4 +46,4 @@ async function bootstrap() {
   await app.listen(process.env.PORT ?? 3033);
 }
 
-bootstrap();
+void bootstrap();
diff --git a/src/product/dto/select-product.dto.ts b/src/product/dto/select-product.dto.ts
index 2eccdd6..2bc6493 100644
--- a/src/product/dto/select-product.dto.ts
+++ b/src/product/dto/select-product.dto.ts
@@ -2,3 +2,11 @@ import { createZodDto } from 'nestjs-zod';
 import { ProductSchema } from '../../../prisma/generated/zod';
 
 export class SelectProductDto extends createZodDto(ProductSchema) {}
+
+export class IProductFindMay {
+  result: SelectProductDto[];
+  total: number;
+  page: number;
+  limit: number;
+  totalPage: number;
+}
diff --git a/src/product/product.controller.ts b/src/product/product.controller.ts
index fe6addd..6dacbd9 100644
--- a/src/product/product.controller.ts
+++ b/src/product/product.controller.ts
@@ -1,9 +1,11 @@
 import {
   Body,
   Controller,
+  DefaultValuePipe,
   Delete,
   Get,
   Param,
+  ParseIntPipe,
   Patch,
   Post,
   Query,
@@ -16,8 +18,8 @@ import {
   UpdateProductStatusDto,
 } from './dto/update-product.dto';
 import { ZodValidationPipe } from 'nestjs-zod';
-import { ApiBody, ApiResponse, ApiTags } from '@nestjs/swagger';
-import { SelectProductDto } from './dto/select-product.dto';
+import { ApiBody, ApiQuery, ApiResponse, ApiTags } from '@nestjs/swagger';
+import { IProductFindMay, SelectProductDto } from './dto/select-product.dto';
 
 @ApiTags('Product')
 @Controller('product')
@@ -45,12 +47,26 @@ export class ProductController {
   @Get()
   @ApiResponse({
     status: 200,
-    type: SelectProductDto,
-    isArray: true,
+    type: IProductFindMay,
   })
   @ApiResponse({ status: 403, description: 'Forbidden.' })
-  async findAll(): Promise<SelectProductDto[]> {
-    return this.productService.findAll();
+  @ApiQuery({
+    name: 'page',
+    required: false,
+    type: Number,
+    description: 'Page number',
+  })
+  @ApiQuery({
+    name: 'limit',
+    required: false,
+    type: Number,
+    description: 'Items per page',
+  })
+  async findAll(
+    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
+    @Query('limit', new DefaultValuePipe(5), ParseIntPipe) limit: number,
+  ): Promise<IProductFindMay> {
+    return this.productService.findAll(page, limit);
   }
 
   @Get(':id')
diff --git a/src/product/product.service.ts b/src/product/product.service.ts
index c70c480..7b1de33 100644
--- a/src/product/product.service.ts
+++ b/src/product/product.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
 import { CreatedProductId, CreateProductDto } from './dto/create-product.dto';
 import { UpdateProductDto } from './dto/update-product.dto';
 import { PrismaService } from 'nestjs-prisma';
-import { SelectProductDto } from './dto/select-product.dto';
+import { IProductFindMay, SelectProductDto } from './dto/select-product.dto';
 import { ProductStatusType } from '../../prisma/generated/zod';
 
 @Injectable()
@@ -18,8 +18,24 @@ export class ProductService {
     });
   }
 
-  async findAll(): Promise<SelectProductDto[]> {
-    return this.prismaService.product.findMany();
+  async findAll(page: number, limit: number): Promise<IProductFindMay> {
+    const raw = await this.prismaService.$transaction([
+      this.prismaService.product.count(),
+      this.prismaService.product.findMany({
+        take: limit,
+        skip: limit * (page - 1),
+      }),
+    ]);
+
+    const [total, data] = raw;
+
+    return {
+      result: data,
+      total,
+      page,
+      limit,
+      totalPage: Math.ceil(total / limit),
+    };
   }
 
   async findOne(id: string) {
diff --git a/src/user/dto/create-user.dto.ts b/src/user/dto/create-user.dto.ts
new file mode 100644
index 0000000..13d0990
--- /dev/null
+++ b/src/user/dto/create-user.dto.ts
@@ -0,0 +1,14 @@
+import { createZodDto } from 'nestjs-zod';
+import { UserCreateInputSchema, UserSchema } from 'prisma/generated/zod';
+
+export class CreateUserDto extends createZodDto(UserCreateInputSchema) {}
+
+export class CreatedUserDto extends createZodDto(UserSchema) {}
+
+export class IUserFindMay {
+  result: CreatedUserDto[];
+  total: number;
+  page: number;
+  limit: number;
+  totalPage: number;
+}
diff --git a/src/user/dto/update-user.dto.ts b/src/user/dto/update-user.dto.ts
new file mode 100644
index 0000000..78ab602
--- /dev/null
+++ b/src/user/dto/update-user.dto.ts
@@ -0,0 +1,4 @@
+import { PartialType } from '@nestjs/swagger';
+import { CreateUserDto } from './create-user.dto';
+
+export class UpdateUserDto extends PartialType(CreateUserDto) {}
diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts
new file mode 100644
index 0000000..ab0a43c
--- /dev/null
+++ b/src/user/user.controller.ts
@@ -0,0 +1,100 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+  HttpCode,
+  HttpStatus,
+  Query,
+  DefaultValuePipe,
+  ParseIntPipe,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import {
+  CreatedUserDto,
+  CreateUserDto,
+  IUserFindMay,
+} from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiQuery, ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @ApiResponse({
+    status: 201,
+    description: 'User successfully created',
+    type: CreatedUserDto,
+  })
+  @Post()
+  @HttpCode(HttpStatus.CREATED)
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
+
+  @ApiResponse({
+    status: 200,
+    description: 'Returns a list of users',
+    type: IUserFindMay,
+  })
+  @ApiQuery({
+    name: 'page',
+    required: false,
+    type: Number,
+    description: 'Page number',
+  })
+  @ApiQuery({
+    name: 'limit',
+    required: false,
+    type: Number,
+    description: 'Items per page',
+  })
+  @Get()
+  async findAll(
+    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
+    @Query('limit', new DefaultValuePipe(5), ParseIntPipe) limit: number,
+  ): Promise<IUserFindMay> {
+    return await this.userService.findAll(page, limit);
+  }
+
+  @ApiResponse({
+    status: 200,
+    description: 'Returns the requested user',
+    type: CreatedUserDto,
+  })
+  @ApiResponse({
+    status: 404,
+    description: "User can't be found or something went wrong",
+  })
+  @Get(':id')
+  async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+    return await this.userService.findOne(id);
+  }
+
+  @ApiResponse({
+    status: 404,
+    description: "User can't be found or something went wrong",
+  })
+  @Patch(':id')
+  async update(
+    @Param('id') id: string,
+    @Body() updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    return await this.userService.update(id, updateUserDto);
+  }
+
+  @ApiResponse({
+    status: 404,
+    description: "User can't be found or something went wrong",
+  })
+  @Delete(':id')
+  async remove(
+    @Param('id') id: string,
+  ): Promise<{ id: string; message: string }> {
+    return await this.userService.remove(id);
+  }
+}
diff --git a/src/user/user.module.ts b/src/user/user.module.ts
new file mode 100644
index 0000000..e21d51f
--- /dev/null
+++ b/src/user/user.module.ts
@@ -0,0 +1,9 @@
+import { Module } from '@nestjs/common';
+import { UserService } from './user.service';
+import { UserController } from './user.controller';
+
+@Module({
+  controllers: [UserController],
+  providers: [UserService],
+})
+export class UserModule {}
diff --git a/src/user/user.service.ts b/src/user/user.service.ts
new file mode 100644
index 0000000..5b7769c
--- /dev/null
+++ b/src/user/user.service.ts
@@ -0,0 +1,146 @@
+import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
+import {
+  CreatedUserDto,
+  CreateUserDto,
+  IUserFindMay,
+} from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { PrismaService } from 'nestjs-prisma';
+import * as argon2 from 'argon2';
+import { Prisma } from '@prisma/client';
+
+@Injectable()
+export class UserService {
+  constructor(private readonly prismaService: PrismaService) {}
+
+  async create(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    const hashedPassword = await this.hashPassword(
+      String(createUserDto.password),
+    );
+    const data = await this.prismaService.user.create({
+      data: {
+        ...createUserDto,
+        password: hashedPassword,
+      },
+    });
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async findAll(page: number, limit: number): Promise<IUserFindMay> {
+    const raw = await this.prismaService.$transaction([
+      this.prismaService.user.count(),
+      this.prismaService.user.findMany({
+        take: limit,
+        skip: limit * (page - 1),
+      }),
+    ]);
+
+    const [total, data] = raw;
+
+    const cleanedData = data.map((user) => {
+      return this.hashPasswordInObject(user);
+    });
+
+    return {
+      result: cleanedData,
+      total,
+      page,
+      limit,
+      totalPage: Math.ceil(total / limit),
+    };
+  }
+
+  async findOne(id: string): Promise<CreatedUserDto> {
+    const data = await this.prismaService.user.findUnique({
+      where: {
+        id,
+      },
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.NOT_FOUND,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async update(
+    id: string,
+    updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    if (updateUserDto.password) {
+      const hashedPassword = await this.hashPassword(
+        String(updateUserDto.password),
+      );
+      updateUserDto.password = hashedPassword;
+    }
+
+    try {
+      const data = await this.prismaService.user.update({
+        where: { id },
+        data: updateUserDto,
+      });
+
+      return this.hashPasswordInObject(data);
+    } catch (error) {
+      if (error instanceof Prisma.PrismaClientKnownRequestError) {
+        if (error.code === 'P2025') {
+          throw new HttpException(
+            `User with id ${id} not found`,
+            HttpStatus.NOT_FOUND,
+          );
+        }
+      }
+
+      throw error;
+    }
+  }
+
+  async remove(id: string): Promise<{ id: string; message: string }> {
+    try {
+      const data = await this.prismaService.user.delete({
+        where: {
+          id,
+        },
+      });
+
+      return { id: data.id, message: 'User successfully deleted' };
+    } catch (error) {
+      if (error instanceof Prisma.PrismaClientKnownRequestError) {
+        if (error.code === 'P2025') {
+          throw new HttpException(
+            `User with id ${id} not found`,
+            HttpStatus.NOT_FOUND,
+          );
+        }
+      }
+
+      throw error;
+    }
+  }
+
+  async hashPassword(password: string): Promise<string> {
+    const hash = await argon2.hash(password);
+    return hash;
+  }
+
+  async comparePasswords(hash: string, password: string): Promise<boolean> {
+    const result = await argon2.verify(hash, password);
+    return result;
+  }
+
+  hashPasswordInObject<T>(object: T): T {
+    return {
+      ...object,
+      password: 'hashed_password',
+    };
+  }
+}


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 9**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>src/user/dto/create-user.dto.ts (1)</summary><blockquote>

`1-6`: **Well-structured DTOs with Zod validation**

The DTOs are properly defined using Zod schemas for validation, which ensures type safety and proper request/response handling. The separation between input (`CreateUserDto`) and output (`CreatedUserDto`) DTOs follows best practices.


Consider adding JSDoc comments to describe each DTO's purpose and fields:

```diff
+/**
+ * DTO for creating a new user
+ */
export class CreateUserDto extends createZodDto(UserCreateInputSchema) {}

+/**
+ * DTO representing a user after creation
+ */
export class CreatedUserDto extends createZodDto(UserSchema) {}
```

</blockquote></details>
<details>
<summary>src/user/user.service.ts (4)</summary><blockquote>

`11-25`: **Type assertion for password could be eliminated with better DTO typing**

The type assertion `createUserDto.password as string` on line 13 suggests the DTO typing could be improved. If password is optional in the schema, consider making it required in the CreateUserDto or handle the absence more explicitly.


```diff
- const hashedPassword = await this.hashPassword(
-   createUserDto.password as string,
- );
+ // If password is required in your CreateUserDto, no type assertion needed
+ const hashedPassword = await this.hashPassword(createUserDto.password);
```

---

`27-34`: **Consider adding pagination to findAll method**

The current implementation fetches all users without pagination, which could lead to performance issues as your user base grows. Consider implementing pagination with skip/take parameters.


```diff
- async findAll(): Promise<CreatedUserDto[]> {
+ async findAll(page = 1, limit = 10): Promise<{users: CreatedUserDto[], total: number}> {
    const data = await this.prismaService.user.findMany({
+     skip: (page - 1) * limit,
+     take: limit
    });
+   const total = await this.prismaService.user.count();
    const cleanedData = data.map((user) => {
      return this.hashPasswordInObject(user);
    });

-   return cleanedData;
+   return { users: cleanedData, total };
}
```

---

`102-110`: **Consider adding Argon2 configuration options**

While using Argon2 is great, you should explicitly configure its parameters for optimal security. Argon2 allows customization of memory cost, time cost, and parallelism factors.


```diff
async hashPassword(password: string): Promise<string> {
-  const hash = await argon2.hash(password);
+  const hash = await argon2.hash(password, {
+    type: argon2.argon2id, // Recommended variant
+    memoryCost: 2 ** 16,   // Adjust based on your server capabilities
+    timeCost: 3,           // Iterations
+    parallelism: 1         // Threads
+  });
  return hash;
}
```

---

`112-117`: **Rename hashPasswordInObject to maskPasswordInObject for clarity**

The method name "hashPasswordInObject" is misleading as it doesn't actually hash anything but simply replaces the password with a placeholder string. A more accurate name would improve code readability.


```diff
- hashPasswordInObject<T>(object: T): T {
+ maskPasswordInObject<T>(object: T): T {
  return {
    ...object,
    password: 'hashed_password',
  };
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 7123e797a34696007c20b1b3390b8235f5ebf3f9 and 5a12824432ca329d1016319932a2ab9cd0c1b55c.

</details>

<details>
<summary>⛔ Files ignored due to path filters (2)</summary>

* `package-lock.json` is excluded by `!**/package-lock.json`
* `prisma/generated/zod/index.ts` is excluded by `!**/generated/**`

</details>

<details>
<summary>📒 Files selected for processing (11)</summary>

* `package.json` (3 hunks)
* `prisma/migrations/20250426220749_change_password_field/migration.sql` (1 hunks)
* `prisma/migrations/migration_lock.toml` (1 hunks)
* `prisma/schema.prisma` (1 hunks)
* `src/app.module.ts` (2 hunks)
* `src/main.ts` (4 hunks)
* `src/user/dto/create-user.dto.ts` (1 hunks)
* `src/user/dto/update-user.dto.ts` (1 hunks)
* `src/user/user.controller.ts` (1 hunks)
* `src/user/user.module.ts` (1 hunks)
* `src/user/user.service.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>src/user/user.module.ts (1)</summary><blockquote>

<details>
<summary>src/app.module.ts (1)</summary>

* `Module` (14-50)

</details>

</blockquote></details>
<details>
<summary>src/user/dto/create-user.dto.ts (1)</summary><blockquote>

<details>
<summary>prisma/generated/zod/index.ts (2)</summary>

* `UserCreateInputSchema` (1322-1330)
* `UserSchema` (166-174)

</details>

</blockquote></details>
<details>
<summary>src/user/dto/update-user.dto.ts (1)</summary><blockquote>

<details>
<summary>src/user/dto/create-user.dto.ts (1)</summary>

* `CreateUserDto` (4-4)

</details>

</blockquote></details>
<details>
<summary>src/user/user.controller.ts (2)</summary><blockquote>

<details>
<summary>src/user/dto/create-user.dto.ts (2)</summary>

* `CreateUserDto` (4-4)
* `CreatedUserDto` (6-6)

</details>
<details>
<summary>src/user/dto/update-user.dto.ts (1)</summary>

* `UpdateUserDto` (4-4)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (12)</summary><blockquote>

<details>
<summary>package.json (1)</summary>

`2-2`: <details>
<summary>✅ Verification successful</summary>

**Ensure consistent package rename throughout the codebase.**

The package name was updated to `"bottle-code-backend"`. Please verify that no references to the old name (`"cider-code-backend"`) remain in configuration, documentation, CI/CD scripts, or source files.

---

🏁 Script executed:

```shell
#!/bin/bash
# Verify no leftover references to the old package name
rg -i 'cider-code-backend'
```

Length of output: 26

---



</details>

**No remaining references to the old package name**  
I ran a case-insensitive search for “cider-code-backend” across the repository and found no occurrences. The package rename to `"bottle-code-backend"` is consistently applied.

</details>
<details>
<summary>prisma/schema.prisma (1)</summary>

`103-108`: **Schema aligns with new user model requirements.**

The `User` model correctly defines `id`, `email` (unique), `firstName`, `lastName`, and a required `password` field. The unique constraint on `email` ensures efficient lookups. This change aligns with the corresponding migration script.

</details>
<details>
<summary>src/user/user.module.ts (1)</summary>

`1-9`: **UserModule setup appears correct.**

The `UserController` and `UserService` are declared properly. Since `PrismaModule` is registered as global in `AppModule`, no additional imports are needed here. The module structure follows NestJS conventions.

</details>
<details>
<summary>src/user/dto/update-user.dto.ts (1)</summary>

`1-4`: **UpdateUserDto extends CreateUserDto for partial updates.**

Using `PartialType(CreateUserDto)` from `@nestjs/swagger` is valid for generating optional properties and Swagger metadata. Ensure your Swagger setup reflects the optional nature of these fields in the API docs.

</details>
<details>
<summary>src/app.module.ts (1)</summary>

`12-12`: **Integration of UserModule looks good**

The UserModule is properly imported and added to the AppModule's imports array, making the new user management functionality available throughout the application.



Also applies to: 23-23

</details>
<details>
<summary>prisma/migrations/20250426220749_change_password_field/migration.sql (1)</summary>

`1-10`: <details>
<summary>❓ Verification inconclusive</summary>

**Potential data loss during migration**

This migration renames the password field from `hashedPassword` to `password`, which will cause data loss for existing users. The warnings in the migration file correctly highlight two issues:
1. All data in the `hashedPassword` column will be lost
2. Adding a required column without a default value is problematic if the table has existing data


Consider adding a data migration step if there are existing users in production:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if the User table has existing records that might be affected
echo "Checking if the User table contains records..."
rg -A 5 "User" prisma/schema.prisma
```

Length of output: 372

---



</details>

**Preserve Existing Password Data During Migration**

The current SQL migration (`prisma/migrations/20250426220749_change_password_field/migration.sql`, lines 1–10) drops `hashedPassword` and immediately adds a non-null `password` column. This will:

- Permanently discard all values in `hashedPassword`.
- Fail on non-empty tables because `password` has no default and is required.

To avoid data loss or a broken deploy, please:

- Introduce a data-migration step before dropping `hashedPassword` to populate the new `password` column (e.g., copy `hashedPassword` → `password` or use a temporary nullable column).
- Ensure you handle or re-hash passwords as needed after the copy.
- If resetting all passwords is intentional, document that users will need to set new passwords post-migration.

</details>
<details>
<summary>src/main.ts (2)</summary>

`15-16`: **Consistent rebranding from CIDER to BOTTLE**

The rebranding from "CIDER [CODE]" to "BOTTLE [CODE]" is consistently applied across API documentation titles and slugs.



Also applies to: 33-34

---

`49-49`: **Explicit void keyword for bootstrap**

Using `void bootstrap()` explicitly indicates that the promise returned by bootstrap is intentionally ignored. This is a good practice for clarity.

</details>
<details>
<summary>src/user/dto/create-user.dto.ts (1)</summary>

`4-4`: <details>
<summary>✅ Verification successful</summary>

**Password field security consideration**

The `CreateUserDto` uses `UserCreateInputSchema` which includes a plain text password field. Since you're using Argon2 for password hashing (according to the PR summary), ensure that password hashing is performed in the service layer before storing in the database.


Let's check if password hashing is implemented in the user service:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check how passwords are handled in the user service
echo "Checking for password hashing in user service..."
rg "password" src/user/user.service.ts
```

Length of output: 614

---

🏁 Script executed:

```shell
#!/bin/bash
# Locate and display the UserService implementation to verify password hashing integration
echo "Locating user service file..."
SERVICE_FILE=$(fd --ignore-case "user.service.ts" -c never)
echo "Found service file: $SERVICE_FILE"
echo "Displaying contents around createUser and hashPassword methods..."
sed -n '1,200p' "$SERVICE_FILE"
```

Length of output: 3235

---



</details>

**Password hashing is properly implemented in UserService**

The `create` and `update` methods both call `hashPassword` on the incoming plain-text password before saving it via Prisma, and `hashPassword` uses Argon2. The returned DTOs also mask the password field via `hashPasswordInObject`. No further changes are needed here.

</details>
<details>
<summary>src/user/user.service.ts (1)</summary>

`1-6`: **Good job implementing secure password hashing with Argon2**

The choice of Argon2 for password hashing is excellent as it's currently considered one of the most secure hashing algorithms, significantly more resistant to attacks than bcrypt or PBKDF2.

</details>
<details>
<summary>src/user/user.controller.ts (2)</summary>

`1-14`: **Well-structured imports and good use of NestJS decorators**

The imports are well-organized and the controller properly utilizes NestJS decorators for HTTP methods and parameter binding.

---

`1-58`: **Consider implementing role-based access control for API endpoints**

This user controller doesn't appear to implement any authentication or authorization mechanisms. In a production environment, these endpoints should be protected based on user roles.


How are you planning to secure these user management endpoints? Consider implementing guards and role-based access control to prevent unauthorized access to these sensitive endpoints.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-26T22:47:51Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 0**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>src/user/user.controller.ts (3)</summary><blockquote>

`74-75`: _🛠️ Refactor suggestion_

**Add UUID validation for ID parameter.**

The ID parameter should be validated to ensure it's a valid UUID format. This helps catch invalid IDs early in the request processing pipeline.



```diff
@Get(':id')
- async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+ async findOne(@Param('id', ParseUUIDPipe) id: string): Promise<CreatedUserDto> {
  return await this.userService.findOne(id);
}
```

Don't forget to import ParseUUIDPipe from @nestjs/common:

```diff
import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  HttpCode,
  HttpStatus,
  Query,
  DefaultValuePipe,
  ParseIntPipe,
+ ParseUUIDPipe,
} from '@nestjs/common';
```

---

`78-88`: _🛠️ Refactor suggestion_

**Add UUID validation and success response documentation for update endpoint.**

The update endpoint should validate the ID parameter and include API documentation for the success case.



```diff
@ApiResponse({
  status: 404,
  description: "User can't be found or something went wrong",
})
+@ApiResponse({
+  status: 200,
+  description: 'Returns the updated user',
+  type: CreatedUserDto,
+})
@Patch(':id')
async update(
-  @Param('id') id: string,
+  @Param('id', ParseUUIDPipe) id: string,
  @Body() updateUserDto: UpdateUserDto,
): Promise<CreatedUserDto> {
  return await this.userService.update(id, updateUserDto);
}
```

---

`90-99`: _🛠️ Refactor suggestion_

**Add UUID validation and success response documentation for delete endpoint.**

The delete endpoint should validate the ID parameter and include API documentation for the success case.



```diff
@ApiResponse({
  status: 404,
  description: "User can't be found or something went wrong",
})
+@ApiResponse({
+  status: 200,
+  description: 'User successfully deleted',
+  schema: {
+    type: 'object',
+    properties: {
+      id: { type: 'string' },
+      message: { type: 'string' }
+    }
+  }
+})
@Delete(':id')
async remove(
-  @Param('id') id: string,
+  @Param('id', ParseUUIDPipe) id: string,
): Promise<{ id: string; message: string }> {
  return await this.userService.remove(id);
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (3)</summary><blockquote>

<details>
<summary>src/user/user.service.ts (2)</summary><blockquote>

`135-138`: **Unused method in current implementation.**

The comparePasswords method is implemented but not used in any of the service methods. Consider removing it if it's not needed, or document its purpose for future use.

---

`140-145`: **Consider checking for password property existence.**

The hashPasswordInObject method currently assumes the object has a password property. For more robustness, consider checking if the property exists before attempting to replace it.


```diff
hashPasswordInObject<T>(object: T): T {
  return {
    ...object,
-   password: 'hashed_password',
+   ...(Object.prototype.hasOwnProperty.call(object, 'password') ? { password: 'hashed_password' } : {}),
  };
}
```

</blockquote></details>
<details>
<summary>src/user/user.controller.ts (1)</summary><blockquote>

`35-37`: **Avoid redundant await with return.**

When returning an awaited Promise, the `await` is redundant when it's used with `return` in an async function.


```diff
@Post()
@HttpCode(HttpStatus.CREATED)
async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
-  return await this.userService.create(createUserDto);
+  return this.userService.create(createUserDto);
}
```

This applies to all controller methods. Consider fixing this pattern throughout the controller.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5a12824432ca329d1016319932a2ab9cd0c1b55c and 9fbdc68bf6a398fe971e1b31b30aa0430e1976fc.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `package-lock.json` is excluded by `!**/package-lock.json`

</details>

<details>
<summary>📒 Files selected for processing (4)</summary>

* `package.json` (3 hunks)
* `src/user/dto/create-user.dto.ts` (1 hunks)
* `src/user/user.controller.ts` (1 hunks)
* `src/user/user.service.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* package.json
* src/user/dto/create-user.dto.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (2)</summary>

<details>
<summary>src/user/user.service.ts (2)</summary><blockquote>

<details>
<summary>src/user/dto/create-user.dto.ts (3)</summary>

* `CreateUserDto` (4-4)
* `CreatedUserDto` (6-6)
* `IUserFindMay` (8-14)

</details>
<details>
<summary>src/user/dto/update-user.dto.ts (1)</summary>

* `UpdateUserDto` (4-4)

</details>

</blockquote></details>
<details>
<summary>src/user/user.controller.ts (2)</summary><blockquote>

<details>
<summary>src/user/dto/create-user.dto.ts (3)</summary>

* `CreatedUserDto` (6-6)
* `CreateUserDto` (4-4)
* `IUserFindMay` (8-14)

</details>
<details>
<summary>src/user/dto/update-user.dto.ts (1)</summary>

* `UpdateUserDto` (4-4)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (7)</summary><blockquote>

<details>
<summary>src/user/user.service.ts (5)</summary>

`16-30`: **Good implementation of user creation with password hashing.**

The create method correctly hashes the password using Argon2 before storing it in the database, which is a security best practice. The method also properly masks the password in the returned object.

---

`32-54`: **Well-implemented pagination with efficient transaction usage.**

Using a Prisma transaction to fetch both the count and data in a single database call is efficient. The pagination metadata is properly calculated and returned in a structured response.

---

`63-68`: **Appropriate status code for resource not found.**

Using HttpStatus.NOT_FOUND (404) for missing resources is the correct approach, rather than BAD_REQUEST (400). This follows REST API best practices.

---

`86-104`: **Good error handling pattern for database operations.**

Using a try-catch block with specific error code checking for Prisma's "P2025" (record not found) error is the right approach. This provides clearer error handling compared to the redundant null check approach.

---

`107-128`: **Consistent error handling in the remove method.**

The error handling pattern matches what was implemented in the update method, providing consistency throughout the service.

</details>
<details>
<summary>src/user/user.controller.ts (2)</summary>

`28-37`: **Good API documentation for create endpoint.**

The create endpoint is well-documented with appropriate status code and response type. Setting the HTTP status code to 201 for resource creation follows REST API best practices.

---

`39-62`: **Well-implemented pagination with proper API documentation.**

The findAll endpoint correctly implements pagination with default values and validation. The API documentation is comprehensive, including query parameters description.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-26T23:21:55Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 1**

<details>
<summary>🔭 Outside diff range comments (2)</summary><blockquote>

<details>
<summary>src/product/product.controller.ts (2)</summary><blockquote>

`117-126`: _⚠️ Potential issue_

**Route definition order could lead to unreachable endpoint**

The search endpoint might be unreachable because it's defined after a route with a path parameter (`Get(':id')`). NestJS routes are matched in the order they're defined, so `/product/search` requests would be captured by the `/product/:id` route.


Move the search endpoint definition above the `findOne` method:

```diff
-@Get(':id')
-@ApiResponse({
-  status: 200,
-  type: SelectProductDto,
-})
-@ApiResponse({ status: 403, description: 'Forbidden.' })
-async findOne(@Param('id') id: string) {
-  return this.productService.findOne(id);
-}
-
-@ApiBody({
-  type: UpdateProductDto,
-  description: 'Json structure for product object',
-})
-@ApiResponse({
-  status: 200,
-  type: UpdateProductDto,
-})
-@ApiResponse({ status: 403, description: 'Forbidden.' })
-@Patch(':id')
-async update(
-  @Param('id') id: string,
-  @Body() updateProductDto: UpdateProductDto,
-): Promise<UpdateProductDto> {
-  return this.productService.update(id, updateProductDto);
-}
-
-@Delete(':id')
-async remove(@Param('id') id: string) {
-  return this.productService.remove(id);
-}
-
-@ApiBody({
-  type: UpdateProductStatusDto,
-  description: 'Json structure for product status',
-})
-@ApiResponse({ status: 403, description: 'Forbidden.' })
-@Patch(':id/status')
-async updateStatus(
-  @Param('id') id: string,
-  @Body() status: UpdateProductStatusDto,
-): Promise<UpdateProductDto> {
-  return this.productService.updateStatus(id, status.status);
-}
-
-@Get('search')
+@Get('search')
@ApiResponse({
  status: 200,
  type: SelectProductDto,
  isArray: true,
})
@ApiResponse({ status: 403, description: 'Forbidden.' })
async search(@Query('search') search: string) {
  return this.productService.search(search);
}
+
+@Get(':id')
+@ApiResponse({
+  status: 200,
+  type: SelectProductDto,
+})
+@ApiResponse({ status: 403, description: 'Forbidden.' })
+async findOne(@Param('id') id: string) {
+  return this.productService.findOne(id);
+}
+
+@ApiBody({
+  type: UpdateProductDto,
+  description: 'Json structure for product object',
+})
+@ApiResponse({
+  status: 200,
+  type: UpdateProductDto,
+})
+@ApiResponse({ status: 403, description: 'Forbidden.' })
+@Patch(':id')
+async update(
+  @Param('id') id: string,
+  @Body() updateProductDto: UpdateProductDto,
+): Promise<UpdateProductDto> {
+  return this.productService.update(id, updateProductDto);
+}
+
+@Delete(':id')
+async remove(@Param('id') id: string) {
+  return this.productService.remove(id);
+}
+
+@ApiBody({
+  type: UpdateProductStatusDto,
+  description: 'Json structure for product status',
+})
+@ApiResponse({ status: 403, description: 'Forbidden.' })
+@Patch(':id/status')
+async updateStatus(
+  @Param('id') id: string,
+  @Body() status: UpdateProductStatusDto,
+): Promise<UpdateProductDto> {
+  return this.productService.updateStatus(id, status.status);
+}
```

---

`117-126`: _🛠️ Refactor suggestion_

**Inconsistent API response format for search endpoint**

The `findAll` endpoint now returns a paginated response (`IProductFindMay`), but the `search` endpoint still returns a simple array. This creates an inconsistency in your API.


Consider updating the search endpoint to also use pagination:

1. Update the service method:
```typescript
async search(query: string, page: number, limit: number): Promise<IProductFindMay> {
  const raw = await this.prismaService.$transaction([
    this.prismaService.product.count({
      where: {
        OR: [
          { shortName: { contains: query } },
          { fullName: { contains: query } },
          { gtin: { contains: query } },
        ],
      },
    }),
    this.prismaService.product.findMany({
      where: {
        OR: [
          { shortName: { contains: query } },
          { fullName: { contains: query } },
          { gtin: { contains: query } },
        ],
      },
      take: limit,
      skip: limit * (page - 1),
    }),
  ]);

  const [total, data] = raw;

  return {
    result: data,
    total,
    page,
    limit,
    totalPage: Math.ceil(total / limit),
  };
}
```

2. Update the controller method:
```typescript
@Get('search')
@ApiResponse({
  status: 200,
  type: IProductFindMay,
})
@ApiResponse({ status: 403, description: 'Forbidden.' })
@ApiQuery({
  name: 'search',
  required: true,
  type: String,
  description: 'Search query',
})
@ApiQuery({
  name: 'page',
  required: false,
  type: Number,
  description: 'Page number',
})
@ApiQuery({
  name: 'limit',
  required: false,
  type: Number,
  description: 'Items per page',
})
async search(
  @Query('search') search: string,
  @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
  @Query('limit', new DefaultValuePipe(5), ParseIntPipe) limit: number,
): Promise<IProductFindMay> {
  return this.productService.search(search, page, limit);
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>src/product/dto/select-product.dto.ts (1)</summary><blockquote>

`6-12`: **Naming convention issue: Rename IProductFindMay class**

The class name `IProductFindMay` doesn't follow standard TypeScript naming conventions:
1. The "I" prefix is typically used for interfaces, not classes 
2. "May" appears to be a typo for "Many"


Consider renaming to something more descriptive like:
```diff
-export class IProductFindMay {
+export class PaginatedProductResponse {
   result: SelectProductDto[];
   total: number;
   page: number;
   limit: number;
   totalPage: number;
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 9fbdc68bf6a398fe971e1b31b30aa0430e1976fc and d83b345e63a8bc4db3da78defdf1644ca1df82b8.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `src/product/dto/select-product.dto.ts` (1 hunks)
* `src/product/product.controller.ts` (3 hunks)
* `src/product/product.service.ts` (2 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (2)</summary>

<details>
<summary>src/product/product.service.ts (1)</summary><blockquote>

<details>
<summary>src/product/dto/select-product.dto.ts (1)</summary>

* `IProductFindMay` (6-12)

</details>

</blockquote></details>
<details>
<summary>src/product/product.controller.ts (1)</summary><blockquote>

<details>
<summary>src/product/dto/select-product.dto.ts (1)</summary>

* `IProductFindMay` (6-12)

</details>

</blockquote></details>

</details>

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-26T23:26:39Z

Review comments:
diff_hunk: @@ -32,6 +32,8 @@
     "@nestjs/platform-express": "^11.0.1",
     "@prisma/client": "^6.6.0",
     "@scalar/nestjs-api-reference": "^0.4.7",
+    "argon2": "^0.43.0",
+    "bcrypt": "^5.1.1",
path: package.json
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Validate the necessity of both bcrypt and argon2 dependencies.**

`argon2` is used for password hashing in `UserService`, but `bcrypt` (and its types) may be unused. Confirm whether `bcrypt` is required; if not, consider removing it to reduce package bloat.  





Also applies to: 53-53

---

🏁 Script executed:

```shell
#!/bin/bash
# Check for bcrypt usage in the codebase
rg -l "bcrypt"
```

Length of output: 45

---

🏁 Script executed:

```shell
#!/bin/bash
# Searching for explicit bcrypt imports or requires and direct usage in code
rg -n "require\(['\"]bcrypt['\"]\)" || true
rg -n "import .*bcrypt" || true
rg -n "bcrypt\." -C2 || true
```

Length of output: 111

---



</details>

**Remove unused bcrypt dependency**

Our searches didn’t find any `require('bcrypt')`, `import bcrypt` or direct `bcrypt.` calls in the codebase. It appears you’re exclusively using argon2 for hashing in `UserService`. To reduce package bloat, please:

• Remove the bcrypt entries from package.json (lines 35–36).  
• Remove any related types or references (e.g. in devDependencies around line 53).  
• Run `npm prune` or regenerate your lockfile to clean up package-lock.json.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,118 @@
+import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { PrismaService } from 'nestjs-prisma';
+import * as argon2 from 'argon2';
+
+@Injectable()
+export class UserService {
+  constructor(private readonly prismaService: PrismaService) {}
+
+  async create(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    const hashedPassword = await this.hashPassword(
+      createUserDto.password as string,
+    );
+    const data = await this.prismaService.user.create({
+      data: {
+        ...createUserDto,
+        password: hashedPassword,
+      },
+    });
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async findAll(): Promise<CreatedUserDto[]> {
+    const data = await this.prismaService.user.findMany();
+    const cleanedData = data.map((user) => {
+      return this.hashPasswordInObject(user);
+    });
+
+    return cleanedData;
+  }
+
+  async findOne(id: string): Promise<CreatedUserDto> {
+    const data = await this.prismaService.user.findUnique({
+      where: {
+        id,
+      },
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async update(
+    id: string,
+    updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    if (updateUserDto.password) {
+      const hashedPassword = await this.hashPassword(
+        updateUserDto.password as string,
+      );
+      updateUserDto.password = hashedPassword;
+    }
+
+    const data = await this.prismaService.user.update({
+      where: {
+        id,
+      },
+      data: updateUserDto,
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async remove(id: string): Promise<string> {
+    const data = await this.prismaService.user.delete({
+      where: {
+        id,
+      },
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    return data.id;
+  }
path: src/user/user.service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Same issue with null check after Prisma delete operation**

Similar to the update method, this null check is redundant as Prisma throws an exception if the record doesn't exist. The status code should also be 404 instead of 400 for consistency.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,118 @@
+import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { PrismaService } from 'nestjs-prisma';
+import * as argon2 from 'argon2';
+
+@Injectable()
+export class UserService {
+  constructor(private readonly prismaService: PrismaService) {}
+
+  async create(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    const hashedPassword = await this.hashPassword(
+      createUserDto.password as string,
+    );
+    const data = await this.prismaService.user.create({
+      data: {
+        ...createUserDto,
+        password: hashedPassword,
+      },
+    });
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async findAll(): Promise<CreatedUserDto[]> {
+    const data = await this.prismaService.user.findMany();
+    const cleanedData = data.map((user) => {
+      return this.hashPasswordInObject(user);
+    });
+
+    return cleanedData;
+  }
+
+  async findOne(id: string): Promise<CreatedUserDto> {
+    const data = await this.prismaService.user.findUnique({
+      where: {
+        id,
+      },
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
path: src/user/user.service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Use NOT_FOUND status code instead of BAD_REQUEST for missing resources**

When a resource isn't found, HTTP status code 404 (NOT_FOUND) is more appropriate than 400 (BAD_REQUEST). This helps clients distinguish between malformed requests and missing resources.


```diff
if (!data) {
  throw new HttpException(
    `User with id ${id} can't be found or something went wrong`,
-   HttpStatus.BAD_REQUEST,
+   HttpStatus.NOT_FOUND,
  );
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  async findOne(id: string): Promise<CreatedUserDto> {
    const data = await this.prismaService.user.findUnique({
      where: {
        id,
      },
    });

    if (!data) {
      throw new HttpException(
        `User with id ${id} can't be found or something went wrong`,
        HttpStatus.NOT_FOUND,
      );
    }

    const res = this.hashPasswordInObject(data);

    return res;
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,118 @@
+import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { PrismaService } from 'nestjs-prisma';
+import * as argon2 from 'argon2';
+
+@Injectable()
+export class UserService {
+  constructor(private readonly prismaService: PrismaService) {}
+
+  async create(createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    const hashedPassword = await this.hashPassword(
+      createUserDto.password as string,
+    );
+    const data = await this.prismaService.user.create({
+      data: {
+        ...createUserDto,
+        password: hashedPassword,
+      },
+    });
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async findAll(): Promise<CreatedUserDto[]> {
+    const data = await this.prismaService.user.findMany();
+    const cleanedData = data.map((user) => {
+      return this.hashPasswordInObject(user);
+    });
+
+    return cleanedData;
+  }
+
+  async findOne(id: string): Promise<CreatedUserDto> {
+    const data = await this.prismaService.user.findUnique({
+      where: {
+        id,
+      },
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
+
+  async update(
+    id: string,
+    updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    if (updateUserDto.password) {
+      const hashedPassword = await this.hashPassword(
+        updateUserDto.password as string,
+      );
+      updateUserDto.password = hashedPassword;
+    }
+
+    const data = await this.prismaService.user.update({
+      where: {
+        id,
+      },
+      data: updateUserDto,
+    });
+
+    if (!data) {
+      throw new HttpException(
+        `User with id ${id} can't be found or something went wrong`,
+        HttpStatus.BAD_REQUEST,
+      );
+    }
+
+    const res = this.hashPasswordInObject(data);
+
+    return res;
+  }
path: src/user/user.service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Unnecessary null check after Prisma update operation**

The check on line 73 is redundant because Prisma's update method already throws a PrismaClientKnownRequestError if the record doesn't exist. Consider catching the specific Prisma exception instead and transforming it to an appropriate HTTP exception.


```diff
- const data = await this.prismaService.user.update({
-   where: {
-     id,
-   },
-   data: updateUserDto,
- });
-
- if (!data) {
-   throw new HttpException(
-     `User with id ${id} can't be found or something went wrong`,
-     HttpStatus.BAD_REQUEST,
-   );
- }
+ try {
+   const data = await this.prismaService.user.update({
+     where: { id },
+     data: updateUserDto,
+   });
+   
+   return this.hashPasswordInObject(data);
+ } catch (error) {
+   if (error.code === 'P2025') { // Prisma "Record not found" error
+     throw new HttpException(
+       `User with id ${id} not found`,
+       HttpStatus.NOT_FOUND,
+     );
+   }
+   throw error;
+ }
```


> Committable suggestion skipped: line range outside the PR's diff.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @Post()
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
+
+  @Get()
+  async findAll(): Promise<CreatedUserDto[]> {
+    return await this.userService.findAll();
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Get(':id')
+  async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+    return await this.userService.findOne(id);
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Patch(':id')
+  async update(
+    @Param('id') id: string,
+    @Body() updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    return await this.userService.update(id, updateUserDto);
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Delete(':id')
+  async remove(@Param('id') id: string): Promise<string> {
+    return await this.userService.remove(id);
+  }
path: src/user/user.controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Standardize delete response and add UUID validation**

The delete endpoint should return a standardized response object rather than just the ID string, and the ID parameter should be validated.


```diff
@ApiResponse({
  status: 400,
  description: "User can't be found or something went wrong",
})
+ @ApiResponse({
+   status: 200,
+   description: 'User successfully deleted',
+   schema: {
+     type: 'object',
+     properties: {
+       id: { type: 'string' },
+       message: { type: 'string' }
+     }
+   }
+ })
@Delete(':id')
- async remove(@Param('id') id: string): Promise<string> {
+ async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise<{id: string, message: string}> {
-  return await this.userService.remove(id);
+  const deletedId = await this.userService.remove(id);
+  return { id: deletedId, message: 'User successfully deleted' };
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  @ApiResponse({
    status: 400,
    description: "User can't be found or something went wrong",
  })
  @ApiResponse({
    status: 200,
    description: 'User successfully deleted',
    schema: {
      type: 'object',
      properties: {
        id: { type: 'string' },
        message: { type: 'string' }
      }
    }
  })
  @Delete(':id')
  async remove(
    @Param('id', new ParseUUIDPipe()) id: string
  ): Promise<{ id: string; message: string }> {
    const deletedId = await this.userService.remove(id);
    return { id: deletedId, message: 'User successfully deleted' };
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @Post()
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
+
+  @Get()
+  async findAll(): Promise<CreatedUserDto[]> {
+    return await this.userService.findAll();
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Get(':id')
+  async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+    return await this.userService.findOne(id);
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Patch(':id')
+  async update(
+    @Param('id') id: string,
+    @Body() updateUserDto: UpdateUserDto,
+  ): Promise<CreatedUserDto> {
+    return await this.userService.update(id, updateUserDto);
+  }
path: src/user/user.controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add UUID validation for update endpoint and success response documentation**

Similar to the findOne endpoint, the update endpoint's ID parameter should be validated, and the successful response should be documented.


```diff
@ApiResponse({
  status: 400,
  description: "User can't be found or something went wrong",
})
+ @ApiResponse({
+   status: 200,
+   description: 'Returns the updated user',
+   type: CreatedUserDto,
+ })
@Patch(':id')
async update(
-  @Param('id') id: string,
+  @Param('id', new ParseUUIDPipe()) id: string,
  @Body() updateUserDto: UpdateUserDto,
): Promise<CreatedUserDto> {
  return await this.userService.update(id, updateUserDto);
}
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @Post()
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
path: src/user/user.controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add HTTP status code and API documentation for successful creation**

The endpoint is missing status code decoration and OpenAPI documentation for the successful response. This would improve API documentation and client expectations.


```diff
+ @ApiResponse({
+   status: 201,
+   description: 'User successfully created',
+   type: CreatedUserDto,
+ })
@Post()
+ @HttpCode(HttpStatus.CREATED)
async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
  return await this.userService.create(createUserDto);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  @ApiResponse({
    status: 201,
    description: 'User successfully created',
    type: CreatedUserDto,
  })
  @Post()
  @HttpCode(HttpStatus.CREATED)
  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
    return await this.userService.create(createUserDto);
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @Post()
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
+
+  @Get()
+  async findAll(): Promise<CreatedUserDto[]> {
+    return await this.userService.findAll();
+  }
+
+  @ApiResponse({
+    status: 400,
+    description: "User can't be found or something went wrong",
+  })
+  @Get(':id')
+  async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+    return await this.userService.findOne(id);
+  }
path: src/user/user.controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add UUID validation for ID parameter and success response documentation**

The ID parameter should be validated, and successful responses should be documented for better API quality and documentation.


```diff
@ApiResponse({
  status: 400,
  description: "User can't be found or something went wrong",
})
+ @ApiResponse({
+   status: 200,
+   description: 'Returns the requested user',
+   type: CreatedUserDto,
+ })
@Get(':id')
- async findOne(@Param('id') id: string): Promise<CreatedUserDto> {
+ async findOne(@Param('id', new ParseUUIDPipe()) id: string): Promise<CreatedUserDto> {
  return await this.userService.findOne(id);
}
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+import {
+  Controller,
+  Get,
+  Post,
+  Body,
+  Patch,
+  Param,
+  Delete,
+} from '@nestjs/common';
+import { UserService } from './user.service';
+import { CreatedUserDto, CreateUserDto } from './dto/create-user.dto';
+import { UpdateUserDto } from './dto/update-user.dto';
+import { ApiResponse } from '@nestjs/swagger';
+
+@Controller('user')
+export class UserController {
+  constructor(private readonly userService: UserService) {}
+
+  @Post()
+  async create(@Body() createUserDto: CreateUserDto): Promise<CreatedUserDto> {
+    return await this.userService.create(createUserDto);
+  }
+
+  @Get()
+  async findAll(): Promise<CreatedUserDto[]> {
+    return await this.userService.findAll();
+  }
path: src/user/user.controller.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add API documentation and implement pagination for findAll endpoint**

This endpoint should include pagination to handle large datasets efficiently and should have proper OpenAPI documentation.


```diff
+ @ApiResponse({
+   status: 200,
+   description: 'Returns a list of users',
+   type: [CreatedUserDto],
+ })
+ @ApiQuery({ name: 'page', required: false, type: Number, description: 'Page number' })
+ @ApiQuery({ name: 'limit', required: false, type: Number, description: 'Items per page' })
@Get()
- async findAll(): Promise<CreatedUserDto[]> {
+ async findAll(
+   @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
+   @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
+ ): Promise<{users: CreatedUserDto[], total: number}> {
-   return await this.userService.findAll();
+   return await this.userService.findAll(page, limit);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  @ApiResponse({
    status: 200,
    description: 'Returns a list of users',
    type: [CreatedUserDto],
  })
  @ApiQuery({ name: 'page', required: false, type: Number, description: 'Page number' })
  @ApiQuery({ name: 'limit', required: false, type: Number, description: 'Items per page' })
  @Get()
  async findAll(
    @Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number,
    @Query('limit', new DefaultValuePipe(10), ParseIntPipe) limit: number,
  ): Promise<{ users: CreatedUserDto[]; total: number }> {
    return await this.userService.findAll(page, limit);
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T22:47:51Z
author_association: NONE
diff_hunk: @@ -18,8 +18,24 @@ export class ProductService {
     });
   }
 
-  async findAll(): Promise<SelectProductDto[]> {
-    return this.prismaService.product.findMany();
+  async findAll(page: number, limit: number): Promise<IProductFindMay> {
+    const raw = await this.prismaService.$transaction([
+      this.prismaService.product.count(),
+      this.prismaService.product.findMany({
+        take: limit,
+        skip: limit * (page - 1),
+      }),
+    ]);
+
+    const [total, data] = raw;
+
+    return {
+      result: data,
+      total,
+      page,
+      limit,
+      totalPage: Math.ceil(total / limit),
+    };
path: src/product/product.service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add pagination parameter validation**

The implementation of pagination is efficient, using a transaction to fetch the count and data in a single database round-trip. However, there's no validation to ensure that `page` and `limit` parameters are positive values.


Add parameter validation to prevent unexpected behavior:

```diff
async findAll(page: number, limit: number): Promise<IProductFindMay> {
+  if (page <= 0) {
+    throw new BadRequestException('Page must be a positive number');
+  }
+  if (limit <= 0) {
+    throw new BadRequestException('Limit must be a positive number');
+  }

  const raw = await this.prismaService.$transaction([
    this.prismaService.product.count(),
    this.prismaService.product.findMany({
      take: limit,
      skip: limit * (page - 1),
    }),
  ]);

  const [total, data] = raw;

  return {
    result: data,
    total,
    page,
    limit,
    totalPage: Math.ceil(total / limit),
  };
}
```

Don't forget to import `BadRequestException` from `@nestjs/common`.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  async findAll(page: number, limit: number): Promise<IProductFindMay> {
+    if (page <= 0) {
+      throw new BadRequestException('Page must be a positive number');
+    }
+    if (limit <= 0) {
+      throw new BadRequestException('Limit must be a positive number');
+    }
  
    const raw = await this.prismaService.$transaction([
      this.prismaService.product.count(),
      this.prismaService.product.findMany({
        take: limit,
        skip: limit * (page - 1),
      }),
    ]);
  
    const [total, data] = raw;
  
    return {
      result: data,
      total,
      page,
      limit,
      totalPage: Math.ceil(total / limit),
    };
  }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-26T23:26:38Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-26T22:45:10Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This update introduces a comprehensive user management feature to the application. It adds a dedicated user module, service, controller, and Data Transfer Objects (DTOs) for handling user creation, retrieval, updating, and deletion. The Prisma schema and migration scripts are updated to rename the user password field and change its handling. Passwords are now securely hashed using Argon2 before storage. The main application module is updated to include the new user module. The project and API branding are changed from "cider-code-backend" to "bottle-code-backend," and related documentation and configuration are updated accordingly. Additionally, product listing endpoints and services are enhanced to support pagination.

## Changes

| File(s)                                                                 | Change Summary                                                                                                                      |
|-------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| `package.json`                                                          | Renamed project to "bottle-code-backend"; added `argon2` dependency.                                                                |
| `prisma/schema.prisma`, `prisma/migrations/20250426220749_change_password_field/migration.sql` | Renamed `hashedPassword` field to `password` in User model; updated migration to drop old column and add new non-nullable password field. |
| `prisma/migrations/migration_lock.toml`                                 | Added a newline at the end of the file; no logic change.                                                                            |
| `src/app.module.ts`                                                     | Imported and included `UserModule` in the main application module.                                                                  |
| `src/main.ts`                                                           | Updated API and project branding from "CIDER [CODE] Backend" to "BOTTLE [CODE] Backend"; updated Swagger docs and API reference titles and slugs; reordered imports; changed `bootstrap()` call to `void bootstrap()`. |
| `src/user/dto/create-user.dto.ts`                                       | Added DTO classes `CreateUserDto` and `CreatedUserDto` and interface `IUserFindMay` for user creation and paginated retrieval.       |
| `src/user/dto/update-user.dto.ts`                                       | Added `UpdateUserDto` class extending `CreateUserDto` with partial properties for updates.                                          |
| `src/user/user.controller.ts`                                           | Added `UserController` class with RESTful CRUD endpoints for user management, including pagination and Swagger API documentation.   |
| `src/user/user.module.ts`                                               | Added `UserModule` declaring `UserController` and `UserService`.                                                                    |
| `src/user/user.service.ts`                                              | Added `UserService` with methods for user CRUD operations, password hashing/verification using Argon2, and DTO transformations.     |
| `src/product/dto/select-product.dto.ts`                                 | Added `IProductFindMay` class for paginated product results.                                                                        |
| `src/product/product.controller.ts`                                     | Modified `findAll` method to accept pagination parameters and return paginated results; updated Swagger docs accordingly.           |
| `src/product/product.service.ts`                                        | Modified `findAll` to return paginated product data with total count and page info.                                                 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant UserController
    participant UserService
    participant PrismaDB

    Client->>UserController: POST /user (CreateUserDto)
    UserController->>UserService: create(CreateUserDto)
    UserService->>UserService: hashPassword(password)
    UserService->>PrismaDB: create user with hashed password
    PrismaDB-->>UserService: created user record
    UserService-->>UserController: CreatedUserDto (password masked)
    UserController-->>Client: CreatedUserDto

    Client->>UserController: GET /user
    UserController->>UserService: findAll(page, limit)
    UserService->>PrismaDB: fetch paginated users and total count
    PrismaDB-->>UserService: user records + total count
    UserService-->>UserController: IUserFindMay (paginated users)
    UserController-->>Client: IUserFindMay

    Client->>UserController: GET /user/:id
    UserController->>UserService: findOne(id)
    UserService->>PrismaDB: fetch user by id
    PrismaDB-->>UserService: user record
    UserService-->>UserController: CreatedUserDto
    UserController-->>Client: CreatedUserDto

    Client->>UserController: PATCH /user/:id (UpdateUserDto)
    UserController->>UserService: update(id, UpdateUserDto)
    UserService->>UserService: hashPassword(password) if provided
    UserService->>PrismaDB: update user
    PrismaDB-->>UserService: updated user record
    UserService-->>UserController: CreatedUserDto
    UserController-->>Client: CreatedUserDto

    Client->>UserController: DELETE /user/:id
    UserController->>UserService: remove(id)
    UserService->>PrismaDB: delete user by id
    PrismaDB-->>UserService: confirmation
    UserService-->>UserController: deletion message
    UserController-->>Client: deletion message
```

## Poem

> 🥕  
> A bottle replaces cider, what a twist in the code,  
> Securely hashed passwords now lighten the load.  
> Users can be managed—create, update, or find,  
> With DTOs and modules all neatly aligned.  
> A hop, a leap, new features abound—  
> In Bottle [CODE] Backend, strong security’s found!  
> 🐇

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=thevladbog/cider-code-backend&utm_content=4):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: socket-security[bot]
created_at: 2025-04-26T22:45:33Z
body: **Review the following changes in direct dependencies.** Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh).

<table>
<thead>
<tr>
<th>Diff</th>
<th width="200px">Package</th>
<th align="center" width="100px">Supply Chain<br/>Security</th>
<th align="center" width="100px">Vulnerability</th>
<th align="center" width="100px">Quality</th>
<th align="center" width="100px">Maintenance</th>
<th align="center" width="100px">License</th>
</tr>
</thead>
<tbody>
<tr><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/diff-added.svg" title="Added" alt="Added" width="20" height="20"></a></td><td><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010">argon2@​0.43.0</a></td><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Supply Chain Security" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Vulnerability" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Quality" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/score-100.svg" title="Maintenance" width="40" height="40" alt="100"></a></td><td align="center"><a href="https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies&dependency_item_key=25178894010"><img src="https://github-app-statics.socket.dev/score-100.svg" title="License" width="40" height="40" alt="100"></a></td></tr>
</tbody>
</table>

[View full report](https://socket.dev/dashboard/org/thevladbog/diff/0caaef0c-f630-4b26-97bc-d9aa68308351/d0b8d8b0-ced9-4ade-96a2-3a6a32bcea20?tab=dependencies)

<!-- overview-comment -->
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-04-26T23:24:44Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=thevladbog_cider-code-backend&pullRequest=4) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=thevladbog_cider-code-backend&pullRequest=4&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=thevladbog_cider-code-backend&pullRequest=4&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=thevladbog_cider-code-backend&pullRequest=4&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=thevladbog_cider-code-backend&pullRequest=4&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=thevladbog_cider-code-backend&pullRequest=4&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=thevladbog_cider-code-backend&pullRequest=4)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-09T20:14:49Z
body: :tada: This PR is included in version 1.0.0-beta.1 :tada:

The release is available on [GitHub release](https://github.com/thevladbog/cider-code-backend/releases/tag/v1.0.0-beta.1)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-10T18:27:16Z
body: :tada: This PR is included in version 1.0.0-beta.1 :tada:

The release is available on [GitHub release](https://github.com/thevladbog/cider-code-backend/releases/tag/v1.0.0-beta.1)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-06-09T22:05:07Z
body: :tada: This PR is included in version 1.0.0 :tada:

The release is available on [GitHub release](https://github.com/thevladbog/cider-code-backend/releases/tag/v1.0.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: NONE