Skip to content
Draft
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
668 changes: 616 additions & 52 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,22 @@
"prisma:reset": "prisma migrate reset && prisma db seed"
},
"dependencies": {
"@nestjs/class-transformer": "^0.4.0",
"@nestjs/class-validator": "^0.13.4",
"@nestjs/common": "^11.1.19",
"@nestjs/config": "^4.0.4",
"@nestjs/core": "^11.1.19",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/swagger": "^11.3.0",
"@nestjs/typeorm": "^11.0.1",
"@prisma/adapter-pg": "^7.7.0",
"@prisma/client": "^7.7.0",
"pg": "^8.20.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"swagger-ui-express": "^5.0.1"
"sanitize-html": "^2.17.3",
"swagger-ui-express": "^5.0.1",
"typeorm": "^0.3.28"
Comment thread
MCSwainConnor marked this conversation as resolved.
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
Expand Down
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ model Product {
size String?
description String?
createdAt DateTime @default(now()) @db.Timestamptz(6)
}
}
16 changes: 16 additions & 0 deletions src/modules/orders/dto/create-order.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IsNotEmpty, IsOptional, IsString, MaxLength } from '@nestjs/class-validator';

export class CreateOrderDto {
@MaxLength(128)
@IsString()
@IsNotEmpty()
name: string;

@IsString()
@IsOptional()
size?: string;

@IsString()
@IsOptional()
description?: string;
}
4 changes: 4 additions & 0 deletions src/modules/orders/dto/update-order.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger';
import { CreateOrderDto } from './create-order.dto';

export class UpdateOrderDto extends PartialType(CreateOrderDto) {}
1 change: 1 addition & 0 deletions src/modules/orders/entities/order.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class Order {}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
20 changes: 20 additions & 0 deletions src/modules/orders/orders.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { OrdersController } from './orders.controller';
import { OrdersService } from './orders.service';

describe('OrdersController', () => {
let controller: OrdersController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [OrdersController],
providers: [OrdersService],
}).compile();

controller = module.get<OrdersController>(OrdersController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
34 changes: 34 additions & 0 deletions src/modules/orders/orders.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Controller, Post, Body, Patch, Param, Delete, Get } from '@nestjs/common';
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create-order.dto';
import { UpdateOrderDto } from './dto/update-order.dto';

@Controller('orders')
export class OrdersController {
constructor(private readonly ordersService: OrdersService) {}

@Post()
create(@Body() createOrderDto: CreateOrderDto) {
return this.ordersService.create(createOrderDto);
}

@Get()
findAll() {
return this.ordersService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.ordersService.findOne(id);
}

@Patch(':id')
update(@Param('id') id: string, @Body() updateOrderDto: UpdateOrderDto) {
return this.ordersService.update(id, updateOrderDto);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.ordersService.remove(id);
Comment thread
MCSwainConnor marked this conversation as resolved.
Outdated
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
11 changes: 11 additions & 0 deletions src/modules/orders/orders.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { OrdersService } from './orders.service';
import { OrdersController } from './orders.controller';
import { PrismaModule } from '../../prisma/prisma.module';

@Module({
imports: [PrismaModule],
controllers: [OrdersController],
providers: [OrdersService],
})
export class OrdersModule {}
18 changes: 18 additions & 0 deletions src/modules/orders/orders.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { OrdersService } from './orders.service';

describe('OrdersService', () => {
let service: OrdersService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [OrdersService],
}).compile();

service = module.get<OrdersService>(OrdersService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
34 changes: 34 additions & 0 deletions src/modules/orders/orders.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { CreateOrderDto } from './dto/create-order.dto';
import { UpdateOrderDto } from './dto/update-order.dto';

@Injectable()
export class OrdersService {
constructor(private readonly prisma: PrismaService) {}

create(createOrderDto: CreateOrderDto) {
const { name, size, description } = createOrderDto;
return this.prisma.create({
name,
size,
description,
});
}

findAll() {
return this.prisma.findAll();
}

findOne(id: string) {
return this.prisma.findOne(id);
}

update(id: string, updateOrderDto: UpdateOrderDto) {
return this.prisma.update(id, updateOrderDto);
}

remove(id: string) {
return this.prisma.remove(id);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align OrdersService with an actual order model or rename it.

The provided Prisma schema has Product but no Order, and these methods delegate to product-backed Prisma CRUD. As written, the orders API will operate on products. Add an Order model plus order-specific Prisma methods, or rename this module/controller/DTOs to products.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/orders/orders.service.ts` around lines 10 - 33, The OrdersService
methods (create, findAll, findOne, update, remove) and DTOs (CreateOrderDto,
UpdateOrderDto) are delegating to this.prisma CRUD for a non-existent Order
model (Prisma schema has Product), so either add an Order model and
corresponding Prisma client methods or rename the module/DTOs/controllers to
operate on Product; to fix, choose one: (A) Add an Order model to Prisma schema
and run generate/migrate, then implement orders-specific prisma methods used in
OrdersService (create, findAll, findOne, update, remove) so they target
prisma.order instead of prisma.product; or (B) Rename OrdersService, controller,
DTOs and references to ProductService/ProductDto and update method calls to use
prisma.product.* so the API consistently operates on Product. Ensure all
references to CreateOrderDto/UpdateOrderDto and OrdersService are updated to
match the chosen model.

}
16 changes: 16 additions & 0 deletions src/prisma/dto/create-prisma.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { IsNotEmpty, IsOptional, IsString, MaxLength } from '@nestjs/class-validator';

export class CreatePrismaDto {
@MaxLength(128)
@IsString()
@IsNotEmpty()
name: string;

@IsString()
@IsOptional()
size?: string;

@IsString()
@IsOptional()
description?: string;
}
Comment on lines +1 to +16
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f "main.ts" src | xargs -I{} sh -c 'echo "=== {} ==="; cat "{}"'

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 798


🏁 Script executed:

cat -n package.json

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 3229


🏁 Script executed:

fd -t f "schema.prisma" . | head -1 | xargs cat

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 649


🏁 Script executed:

fd -t f "*prisma.service.ts" src | xargs cat

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 372


🏁 Script executed:

fd -t f "*.controller.ts" src | xargs grep -l "prisma\|product" -i

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 371


🏁 Script executed:

fd -g "*service.ts" src | head -20

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 236


🏁 Script executed:

fd -g "*controller.ts" src | head -20

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 211


🏁 Script executed:

rg "productsDelegate|PrismaService" src -A 2 -B 2 | head -50

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 3455


🏁 Script executed:

rg "CreatePrismaDto|CreateProductDto" src

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 771


🏁 Script executed:

cat -n src/prisma/prisma.service.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 2481


🏁 Script executed:

cat -n src/prisma/prisma.controller.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 1234


🏁 Script executed:

rg "@nestjs/class-validator" . --type-list | head -5

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 464


🏁 Script executed:

rg "deprecated\|class-validator" . -i | head -20

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 57


🏁 Script executed:

rg "class-validator" package.json -A 2 -B 2

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 245


🏁 Script executed:

rg "deprecated" . --type json

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 361


🏁 Script executed:

head -n 50 package.json | tail -n 30

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 1002


ValidationPipe must be registered in main.ts for decorators to take effect; naming contradicts NestJS conventions.

  1. Critical: No ValidationPipe is configured in main.ts. All validation decorators (including @IsNotEmpty, @MaxLength, etc.) are currently silently ignored at runtime. Add: app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelowed: true })) before app.listen().

  2. Naming smell: The DTO/controller/service are named after the ORM (CreatePrismaDto, PrismaController, PrismaService with route @Controller('prisma')) instead of the entity (Product). This contradicts NestJS conventions where PrismaService should be a thin shared client wrapper in src/modules/prisma/. The entity-specific service should be in src/modules/products/ with route @Controller('products'). Note: correct ProductService and ProductsController already exist in the codebase; consolidate to avoid duplication.

  3. Import source: Switch from @nestjs/class-validator to the standard class-validator package.

  4. Input bounds: Add @MaxLength constraints to optional fields to prevent unbounded input:

    • size: suggest @MaxLength(64)
    • description: suggest @MaxLength(2048)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/dto/create-prisma.dto.ts` around lines 1 - 16, Register the global
ValidationPipe in main.ts (call app.useGlobalPipes(new ValidationPipe({
whitelist: true, forbidNonWhitelowed: true })) before app.listen()) so the
decorators on CreatePrismaDto are enforced; rename and consolidate ORM-named
artifacts to domain names (rename CreatePrismaDto → CreateProductDto, move
PrismaController/PrismaService responsibilities so PrismaService remains the
thin DB client and use ProductService/ProductsController for product routes) to
avoid duplication with existing ProductService/ProductsController; change the
import from `@nestjs/class-validator` to class-validator in the DTO file and add
`@MaxLength`(64) to size and `@MaxLength`(2048) to description on the DTO class
fields to bound input.

4 changes: 4 additions & 0 deletions src/prisma/dto/update-prisma.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/swagger';
import { CreatePrismaDto } from './create-prisma.dto';

export class UpdatePrismaDto extends PartialType(CreatePrismaDto) {}
1 change: 1 addition & 0 deletions src/prisma/entities/prisma.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class Prisma {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Empty placeholder entity — remove or populate.

Prisma is an empty class with no fields, no decorators, and no references elsewhere in the PR. It also shadows the name of the widely used Prisma namespace exported by @prisma/client, which will cause confusing import collisions as the codebase grows. Either delete this file or replace it with a meaningful domain entity (and rename — e.g. Product).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/entities/prisma.entity.ts` at line 1, The file contains an empty
placeholder class named Prisma which both provides no functionality and
conflicts with the `@prisma/client` Prisma namespace; either remove this class
entirely or replace it with a real domain entity and a non-conflicting name
(e.g., rename class Prisma to Product and add appropriate fields/decorators) and
update any imports accordingly so the shadowed Prisma symbol is eliminated.

20 changes: 20 additions & 0 deletions src/prisma/prisma.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaController } from './prisma.controller';
import { PrismaService } from './prisma.service';

describe('PrismaController', () => {
let controller: PrismaController;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [PrismaController],
providers: [PrismaService],
}).compile();

controller = module.get<PrismaController>(PrismaController);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});
});
Comment on lines +1 to +20
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect PrismaService to see whether it connects on init.
fd -t f "prisma.service.ts" | xargs -I{} sh -c 'echo "=== {} ==="; cat "{}"'

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 2658


Mock PrismaService to avoid real database connection in tests.

PrismaService extends PrismaClient and calls $connect() during module initialization. Providing it directly in providers will attempt a real database connection, failing the test. Use a mock instead:

Suggested fix
-    const module: TestingModule = await Test.createTestingModule({
-      controllers: [PrismaController],
-      providers: [PrismaService],
-    }).compile();
+    const module: TestingModule = await Test.createTestingModule({
+      controllers: [PrismaController],
+      providers: [
+        {
+          provide: PrismaService,
+          useValue: {
+            create: jest.fn(),
+            findAll: jest.fn(),
+            findOne: jest.fn(),
+            update: jest.fn(),
+            remove: jest.fn(),
+          },
+        },
+      ],
+    }).compile();

Additionally, the single toBeDefined assertion provides no real coverage. Add tests for each CRUD handler's delegation to the service.

📝 Committable suggestion

‼️ 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.

Suggested change
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaController } from './prisma.controller';
import { PrismaService } from './prisma.service';
describe('PrismaController', () => {
let controller: PrismaController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [PrismaController],
providers: [PrismaService],
}).compile();
controller = module.get<PrismaController>(PrismaController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaController } from './prisma.controller';
import { PrismaService } from './prisma.service';
describe('PrismaController', () => {
let controller: PrismaController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [PrismaController],
providers: [
{
provide: PrismaService,
useValue: {
create: jest.fn(),
findAll: jest.fn(),
findOne: jest.fn(),
update: jest.fn(),
remove: jest.fn(),
},
},
],
}).compile();
controller = module.get<PrismaController>(PrismaController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.controller.spec.ts` around lines 1 - 20, Replace the real
PrismaService provider in the PrismaController test with a mock that stubs out
PrismaService methods (and prevents PrismaClient $connect from being called):
instead of listing PrismaService in providers, provide a mocked value for the
token PrismaService that implements the service methods used by PrismaController
(e.g., create, findAll, findOne, update, remove) and any $connect/$disconnect
no-op, so the test never opens a real DB connection; then add unit tests that
call PrismaController.create / findAll / findOne / update / remove (or the
actual CRUD handler names on PrismaController) and assert they delegate to the
mocked PrismaService methods (using spies/expect calls and returned mock values)
rather than only checking controller toBeDefined.

34 changes: 34 additions & 0 deletions src/prisma/prisma.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import { CreatePrismaDto } from './dto/create-prisma.dto';
import { UpdatePrismaDto } from './dto/update-prisma.dto';

@Controller('prisma')
export class PrismaController {
constructor(private readonly prismaService: PrismaService) {}

@Post()
create(@Body() createPrismaDto: CreatePrismaDto) {
return this.prismaService.create(createPrismaDto);
}

@Get()
findAll() {
return this.prismaService.findAll();
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.prismaService.findOne(id);
}

@Patch(':id')
update(@Param('id') id: string, @Body() updatePrismaDto: UpdatePrismaDto) {
return this.prismaService.update(id, updatePrismaDto);
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.prismaService.remove(id);
Comment on lines +22 to +34
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify raw id params and UUID-backed schema fields.
rg -n -C2 --type=ts "@Param\\('id'\\) id: string|ParseUUIDPipe"
rg -n -C2 '@db\\.Uuid|@default\\(dbgenerated\\("gen_random_uuid\\(\\)"\\)\\)'

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 1958


🏁 Script executed:

# Find and examine the Prisma schema file
find . -name "*.prisma" -type f

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 97


🏁 Script executed:

# Check the current imports in prisma.controller.ts
sed -n '1,10p' src/prisma/prisma.controller.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 456


🏁 Script executed:

# Search for UUID field definitions in schema
rg -n "id.*@db\.Uuid|UUID" --type prisma

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 105


🏁 Script executed:

# Check all controllers for similar patterns
rg -l "findOne.*@Param\('id'\)" --type ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 146


🏁 Script executed:

# Read the Prisma schema to check ID field types
cat prisma/schema.prisma

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 649


🏁 Script executed:

# Check orders.controller.ts imports
sed -n '1,10p' src/modules/orders/orders.controller.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 452


Add UUID validation to route parameters.

The Prisma schema defines UUID IDs (@db.Uuid), but route handlers accept any string without validation. This affects both src/prisma/prisma.controller.ts and src/modules/orders/orders.controller.ts. Add ParseUUIDPipe to return 400 for malformed IDs instead of leaking Prisma/database errors.

Proposed fix (src/prisma/prisma.controller.ts)
-import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
+import { Controller, Get, Post, Body, Patch, Param, Delete, ParseUUIDPipe } from '@nestjs/common';
 
   `@Get`(':id')
-  findOne(`@Param`('id') id: string) {
+  findOne(`@Param`('id', ParseUUIDPipe) id: string) {
     return this.prismaService.findOne(id);
   }
 
   `@Patch`(':id')
-  update(`@Param`('id') id: string, `@Body`() updatePrismaDto: UpdatePrismaDto) {
+  update(`@Param`('id', ParseUUIDPipe) id: string, `@Body`() updatePrismaDto: UpdatePrismaDto) {
     return this.prismaService.update(id, updatePrismaDto);
   }
 
   `@Delete`(':id')
-  remove(`@Param`('id') id: string) {
+  remove(`@Param`('id', ParseUUIDPipe) id: string) {
     return this.prismaService.remove(id);
   }

Apply the same changes to src/modules/orders/orders.controller.ts.

📝 Committable suggestion

‼️ 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.

Suggested change
@Get(':id')
findOne(@Param('id') id: string) {
return this.prismaService.findOne(id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updatePrismaDto: UpdatePrismaDto) {
return this.prismaService.update(id, updatePrismaDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.prismaService.remove(id);
import { Controller, Get, Post, Body, Patch, Param, Delete, ParseUUIDPipe } from '@nestjs/common';
`@Get`(':id')
findOne(`@Param`('id', ParseUUIDPipe) id: string) {
return this.prismaService.findOne(id);
}
`@Patch`(':id')
update(`@Param`('id', ParseUUIDPipe) id: string, `@Body`() updatePrismaDto: UpdatePrismaDto) {
return this.prismaService.update(id, updatePrismaDto);
}
`@Delete`(':id')
remove(`@Param`('id', ParseUUIDPipe) id: string) {
return this.prismaService.remove(id);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.controller.ts` around lines 20 - 32, Add UUID validation to
the route params by importing ParseUUIDPipe from `@nestjs/common` and applying it
to the id route parameters in the PrismaController methods findOne, update, and
remove (i.e., change `@Param`('id') id: string to `@Param`('id', new
ParseUUIDPipe()) id: string) so malformed IDs return 400 instead of reaching
Prisma; make the identical change in the OrdersController methods that accept an
id param (import ParseUUIDPipe there as well and apply new ParseUUIDPipe() to
the id `@Param`).

}
Comment on lines +8 to +35
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where the Prisma controller is registered and imported.
rg -n -C3 --type=ts "@Controller\\('prisma'\\)|controllers:\\s*\\[PrismaController\\]|imports:\\s*\\[PrismaModule\\]"

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 2284


Remove PrismaController from the module's controllers array.

The PrismaModule currently registers PrismaController, exposing raw CRUD endpoints under /prisma that bypass domain semantics. This creates a public infrastructure layer alongside domain APIs. Keep PrismaModule provider-only by exporting only PrismaService, allowing domain-specific controllers (e.g., ProductsController, OrdersController) to handle HTTP routing with explicit business logic and protections.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.controller.ts` around lines 6 - 33, Remove PrismaController
from the PrismaModule controllers array and ensure PrismaModule only registers
and exports the PrismaService provider; locate the PrismaModule class (symbol
PrismaModule) and remove PrismaController from its controllers metadata, keeping
PrismaService in the providers and exports lists so domain modules can inject
PrismaService while HTTP routing remains with domain controllers (e.g.,
ProductsController, OrdersController).

}
Comment on lines +1 to +36
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP --type=ts -C2 '\bPrismaController\b'
rg -nP --type=ts -C3 'controllers\s*:\s*\[' src/prisma src/app.module.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 3178


Misleading naming and unauthenticated CRUD surface.

The PrismaController concern has been clarified:

  • Correction: The controller IS registered in PrismaModule.controllers (line 6 of src/prisma/prisma.module.ts), so it is not dead code.

However, a design concern remains:

  • Per PrismaService, every method delegates to productsDelegate(), meaning /prisma provides an unauthenticated CRUD interface over Products with misleading naming. The @ApiExcludeController() decorator hides it from Swagger documentation but does not prevent runtime access.

If /prisma is intended as an internal/temporary endpoint, consider adding an admin guard (@UseGuards(AdminGuard)) or moving the logic to ProductsController to avoid confusion and unintended exposure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.controller.ts` around lines 1 - 36, PrismaController is
exposing an unauthenticated CRUD surface over Products (via prismaService ->
productsDelegate) with a misleading name; either secure it or remove/move it:
add an authentication/authorization guard (e.g., annotate the PrismaController
class with `@UseGuards`(AdminGuard) and import/provide AdminGuard) so only admins
can access its create/findAll/findOne/update/remove methods, or move the
create/findAll/findOne/update/remove delegations into the existing
ProductsController and remove PrismaController from PrismaModule.controllers to
avoid duplicate/hidden endpoints; update module registrations and imports
accordingly.

10 changes: 10 additions & 0 deletions src/prisma/prisma.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
import { PrismaController } from './prisma.controller';

@Module({
controllers: [PrismaController],
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
Comment on lines +1 to +10
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Mixing infrastructure and feature concerns in one module.

PrismaModule simultaneously (a) exports PrismaService as shared infrastructure for other modules (OrdersModule, ProductModule both import it) and (b) registers a PrismaController that exposes product CRUD endpoints. These should be split:

  • PrismaModule → only providers: [PrismaService] + exports: [PrismaService] (infra, reusable).
  • A dedicated ProductsModulecontrollers: [ProductsController], providers: [ProductsService], imports: [PrismaModule].

Also consider marking PrismaModule as @Global() if every feature module will import it, so you don't have to add it to each imports array.

🔧 Suggested shape
 import { Module } from '@nestjs/common';
 import { PrismaService } from './prisma.service';
-import { PrismaController } from './prisma.controller';

+@Global()
 `@Module`({
-  controllers: [PrismaController],
   providers: [PrismaService],
   exports: [PrismaService],
 })
 export class PrismaModule {}

(and move the controller to a new ProductsModule).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.module.ts` around lines 1 - 10, PrismaModule currently
mixes infra and feature concerns: remove PrismaController from PrismaModule so
PrismaModule only provides and exports PrismaService (keep providers:
[PrismaService] and exports: [PrismaService]) and optionally mark PrismaModule
with `@Global`() if you want it available app-wide; create a new ProductsModule
that registers PrismaController (rename/move PrismaController to
ProductsController if appropriate) and its feature provider ProductsService, and
import PrismaModule into ProductsModule (ProductsModule: controllers:
[ProductsController], providers: [ProductsService], imports: [PrismaModule]);
ensure any modules that used PrismaController now import ProductsModule instead.

18 changes: 18 additions & 0 deletions src/prisma/prisma.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService } from './prisma.service';

describe('PrismaService', () => {
let service: PrismaService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PrismaService],
}).compile();

service = module.get<PrismaService>(PrismaService);
});

it('should be defined', () => {
expect(service).toBeDefined();
});
});
71 changes: 71 additions & 0 deletions src/prisma/prisma.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// src/prisma/prisma.service.ts
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient } from '../generated/prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { CreatePrismaDto } from './dto/create-prisma.dto';
import { UpdatePrismaDto } from './dto/update-prisma.dto';

type ProductRecord = {
id: string;
name: string;
size: string | null;
description: string | null;
createdAt: Date;
};

type ProductsDelegate = {
create(args: { data: CreatePrismaDto }): Promise<ProductRecord>;
findMany(): Promise<ProductRecord[]>;
findUnique(args: { where: { id: string } }): Promise<ProductRecord | null>;
update(args: { where: { id: string }; data: UpdatePrismaDto }): Promise<ProductRecord>;
delete(args: { where: { id: string } }): Promise<ProductRecord>;
};

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
constructor() {
super({
adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }),
});
}
Comment on lines +26 to +30
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate DATABASE_URL before instantiating PrismaPg.

process.env.DATABASE_URL is typed as string | undefined. If the env var is missing (e.g. .env not loaded in a given environment), PrismaPg receives undefined as connectionString and the failure mode is a confusing connection/driver error rather than a clear startup error.

Proposed fix
   constructor() {
+    const connectionString = process.env.DATABASE_URL;
+    if (!connectionString) {
+      throw new Error('DATABASE_URL is not set');
+    }
     super({
-      adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }),
+      adapter: new PrismaPg({ connectionString }),
     });
   }

Or, preferably, wire this through Nest's ConfigModule with a validation schema so all required env vars fail fast on boot.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.service.ts` around lines 26 - 30, The constructor in
PrismaService currently passes process.env.DATABASE_URL (typed string |
undefined) directly into new PrismaPg which can produce confusing driver errors
when the env var is missing; update the constructor to validate that
process.env.DATABASE_URL is a non-empty string and throw a clear startup Error
if missing (or better, refactor to inject Nest's ConfigService and read a
validated DATABASE_URL from a ConfigModule validation schema) before
instantiating new PrismaPg so PrismaPg never receives undefined.

async onModuleInit() {
await this.$connect();
}
async onModuleDestroy() {
await this.$disconnect();
}

private productsDelegate(): ProductsDelegate {
const prismaClient = this as unknown as { products: ProductsDelegate };
return prismaClient.products;
}

create(createPrismaDto: CreatePrismaDto) {
return this.productsDelegate().create({
data: createPrismaDto,
});
}

findAll() {
return this.productsDelegate().findMany();
}

findOne(id: string) {
return this.productsDelegate().findUnique({
where: { id },
});
}

update(id: string, updatePrismaDto: UpdatePrismaDto) {
return this.productsDelegate().update({
where: { id },
data: updatePrismaDto,
});
}

remove(id: string) {
return this.productsDelegate().delete({
where: { id },
});
}
Comment on lines +38 to +70
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the generated delegate name and that no @@map renames the table.
fd -t f 'schema.prisma' --exec cat {}
echo '---'
rg -nP '\b(product|products)\s*:' --type=ts -g '!**/generated/**'

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 877


🏁 Script executed:

# Check the full prisma.service.ts to see all CRUD methods and type definition
fd -t f 'prisma.service.ts' -path '*/src/prisma/*' --exec cat {}

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 243


🏁 Script executed:

# Check the test file to see what is actually being tested
fd -t f 'prisma.service.spec.ts' --exec cat {}

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 994


🏁 Script executed:

# Check if there are any integration tests that hit the CRUD endpoints
fd -t f '.spec.ts' --exec rg -l 'create|findAll|findOne|update|remove' {} \; | head -20

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 433


🏁 Script executed:

# Get full prisma.service.ts content
cat -n src/prisma/prisma.service.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 2481


🏁 Script executed:

# Check app.e2e-spec.ts to see if it has integration tests covering the CRUD endpoints
cat -n test/app.e2e-spec.ts

Repository: Tiffinger-Thiel-GmbH/Merch-Shop

Length of output: 1002


Critical: prismaClient.products is undefined — all CRUD methods will throw at runtime.

The schema defines model Product (singular, no @@map), so Prisma generates the delegate as prisma.product, not prisma.products. The as unknown as { products: ProductsDelegate } cast silences TypeScript, but at runtime prismaClient.products is undefined. Calling .create(), .findMany(), .findUnique(), .update(), or .delete() on undefined throws TypeError: Cannot read properties of undefined.

All five CRUD methods (create, findAll, findOne, update, remove) will fail on the first request. The test suite does not catch this because prisma.service.spec.ts only asserts the service is defined, and app.e2e-spec.ts does not test any CRUD endpoints.

Fix: Rename the type and method to singular (ProductDelegate and productDelegate()), update the cast to { product: ProductDelegate }, and update all five call sites. Better: drop the as unknown as cast entirely and access this.product directly, letting the compiler enforce correctness.

Add an integration test that invokes one of the CRUD methods to catch this in the future.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.service.ts` around lines 38 - 70, The service currently
accesses prismaClient.products which is undefined at runtime; rename the helper
and usages to use the singular delegate (e.g., change productsDelegate() to
productDelegate(), update the cast/type to { product: ProductDelegate } or,
better, remove the unsafe "as unknown as" cast and directly access
this.product), then update all call sites (create, findAll, findOne, update,
remove) to call productDelegate() (or this.product) so they use the actual
Prisma delegate; finally add an integration test that invokes at least one CRUD
method to prevent regressions.

Comment on lines +43 to +70
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Don't put domain CRUD on PrismaService.

PrismaService should be a thin lifecycle wrapper around PrismaClient; placing create/findAll/findOne/update/remove (specific to the Product table) on it couples the shared DB client to one entity and will not scale once a second model is added — you'd end up with either name collisions or a kitchen-sink service. The Products CRUD belongs in a ProductsService that injects PrismaService and calls this.prisma.product.* directly. OrdersService should then either inject its own (future) orders delegate or ProductsService, not reach through PrismaService.

This is also what's producing the orders → products confusion flagged in orders.controller.ts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/prisma/prisma.service.ts` around lines 43 - 70, PrismaService currently
contains domain CRUD (create, findAll, findOne, update, remove) tied to products
via productsDelegate; move these methods out of PrismaService and into a new
ProductsService that injects PrismaService and calls this.prisma.product.create
/ findMany / findUnique / update / delete respectively; remove the
product-specific methods (create, findAll, findOne, update, remove,
productsDelegate usage) from PrismaService so it remains a thin PrismaClient
lifecycle wrapper, then update controllers (e.g., ProductsController and
OrdersController) to inject ProductsService (or inject PrismaService only when
accessing true DB primitives) so OrdersController no longer reaches through
PrismaService to products.

}
Loading