mirror of
http://172.20.10.11:3000/gitadmin/INSIGHT-MVP.git
synced 2026-06-25 04:56:40 +02:00
feat(crm): add PATCH endpoint for pipeline stages + HTTPS router
- New PATCH /pipelines/:id/stages/:stageId endpoint to update stage name, color, and sortOrder - Added HTTPS (websecure) Traefik router for CRM service - Both requested by frontend developer via INSIGHT-CRM.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f62d032480
commit
c9e2c4a44c
4 changed files with 83 additions and 0 deletions
|
|
@ -39,6 +39,13 @@ services:
|
||||||
- "traefik.http.routers.crm.entrypoints=web"
|
- "traefik.http.routers.crm.entrypoints=web"
|
||||||
- "traefik.http.services.crm.loadbalancer.server.port=3100"
|
- "traefik.http.services.crm.loadbalancer.server.port=3100"
|
||||||
- "traefik.http.routers.crm.middlewares=cors-api@file,security-headers@file"
|
- "traefik.http.routers.crm.middlewares=cors-api@file,security-headers@file"
|
||||||
|
# HTTPS Router
|
||||||
|
- "traefik.http.routers.crm-secure.rule=Host(`172.20.10.59`) && PathPrefix(`/api/v1/crm`)"
|
||||||
|
- "traefik.http.routers.crm-secure.priority=100"
|
||||||
|
- "traefik.http.routers.crm-secure.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.crm-secure.tls=true"
|
||||||
|
- "traefik.http.routers.crm-secure.service=crm"
|
||||||
|
- "traefik.http.routers.crm-secure.middlewares=cors-api@file,security-headers@file"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3100/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3100/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
|
|
|
||||||
29
packages/crm-service/src/pipelines/dto/update-stage.dto.ts
Normal file
29
packages/crm-service/src/pipelines/dto/update-stage.dto.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import {
|
||||||
|
IsString,
|
||||||
|
IsOptional,
|
||||||
|
IsInt,
|
||||||
|
Min,
|
||||||
|
MaxLength,
|
||||||
|
Matches,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
export class UpdateStageDto {
|
||||||
|
@ApiPropertyOptional({ maxLength: 200 })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(200)
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
sortOrder?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Hex-Farbcode, z.B. #3B82F6' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@Matches(/^#[0-9A-Fa-f]{6}$/)
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import {
|
||||||
import { PipelinesService } from './pipelines.service';
|
import { PipelinesService } from './pipelines.service';
|
||||||
import { CreatePipelineDto, CreatePipelineStageDto } from './dto/create-pipeline.dto';
|
import { CreatePipelineDto, CreatePipelineStageDto } from './dto/create-pipeline.dto';
|
||||||
import { UpdatePipelineDto } from './dto/update-pipeline.dto';
|
import { UpdatePipelineDto } from './dto/update-pipeline.dto';
|
||||||
|
import { UpdateStageDto } from './dto/update-stage.dto';
|
||||||
import { CurrentUser, JwtPayload } from '../common/decorators';
|
import { CurrentUser, JwtPayload } from '../common/decorators';
|
||||||
import { TenantGuard } from '../auth/guards/tenant.guard';
|
import { TenantGuard } from '../auth/guards/tenant.guard';
|
||||||
import { singleResponse } from '../common/dto/pagination.dto';
|
import { singleResponse } from '../common/dto/pagination.dto';
|
||||||
|
|
@ -116,6 +117,25 @@ export class PipelinesController {
|
||||||
return singleResponse(stage);
|
return singleResponse(stage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Patch(':id/stages/:stageId')
|
||||||
|
@ApiOperation({ summary: 'Stufe aktualisieren (Name, Farbe, Reihenfolge)' })
|
||||||
|
@ApiParam({ name: 'id', type: 'string', format: 'uuid' })
|
||||||
|
@ApiParam({ name: 'stageId', type: 'string', format: 'uuid' })
|
||||||
|
async updateStage(
|
||||||
|
@CurrentUser() user: JwtPayload,
|
||||||
|
@Param('id', ParseUUIDPipe) pipelineId: string,
|
||||||
|
@Param('stageId', ParseUUIDPipe) stageId: string,
|
||||||
|
@Body() dto: UpdateStageDto,
|
||||||
|
) {
|
||||||
|
const stage = await this.pipelinesService.updateStage(
|
||||||
|
user.tenantId!,
|
||||||
|
pipelineId,
|
||||||
|
stageId,
|
||||||
|
dto,
|
||||||
|
);
|
||||||
|
return singleResponse(stage);
|
||||||
|
}
|
||||||
|
|
||||||
@Delete(':id/stages/:stageId')
|
@Delete(':id/stages/:stageId')
|
||||||
@ApiOperation({ summary: 'Stufe aus Pipeline entfernen' })
|
@ApiOperation({ summary: 'Stufe aus Pipeline entfernen' })
|
||||||
@ApiParam({ name: 'id', type: 'string', format: 'uuid' })
|
@ApiParam({ name: 'id', type: 'string', format: 'uuid' })
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { CrmPrismaService } from '../prisma/crm-prisma.service';
|
import { CrmPrismaService } from '../prisma/crm-prisma.service';
|
||||||
import { CreatePipelineDto } from './dto/create-pipeline.dto';
|
import { CreatePipelineDto } from './dto/create-pipeline.dto';
|
||||||
import { UpdatePipelineDto } from './dto/update-pipeline.dto';
|
import { UpdatePipelineDto } from './dto/update-pipeline.dto';
|
||||||
|
import { UpdateStageDto } from './dto/update-stage.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PipelinesService {
|
export class PipelinesService {
|
||||||
|
|
@ -98,6 +99,32 @@ export class PipelinesService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateStage(
|
||||||
|
tenantId: string,
|
||||||
|
pipelineId: string,
|
||||||
|
stageId: string,
|
||||||
|
dto: UpdateStageDto,
|
||||||
|
) {
|
||||||
|
await this.findOne(tenantId, pipelineId);
|
||||||
|
|
||||||
|
const stage = await this.prisma.pipelineStage.findFirst({
|
||||||
|
where: { id: stageId, pipelineId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!stage) {
|
||||||
|
throw new NotFoundException('Pipeline-Stufe nicht gefunden');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.prisma.pipelineStage.update({
|
||||||
|
where: { id: stageId },
|
||||||
|
data: {
|
||||||
|
...(dto.name !== undefined && { name: dto.name }),
|
||||||
|
...(dto.sortOrder !== undefined && { sortOrder: dto.sortOrder }),
|
||||||
|
...(dto.color !== undefined && { color: dto.color }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async removeStage(tenantId: string, pipelineId: string, stageId: string) {
|
async removeStage(tenantId: string, pipelineId: string, stageId: string) {
|
||||||
await this.findOne(tenantId, pipelineId);
|
await this.findOne(tenantId, pipelineId);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue