feat(scenario): add scenario and scenario step CRUD module

- add ScenarioEntity and ScenarioStepEntity with cascade delete
- step fields: type (login|exec), sessionName (required), execCode, validateCode
- login steps create a named session; exec steps consume it by sessionName
- full CRUD controller under /scenarios and /scenarios/:id/steps
- paginated GET /scenarios with page/limit query params returning { data, total, page, limit }
- register ScenarioModule and entities in AppModule
This commit is contained in:
2026-04-07 14:13:06 +03:00
parent 5ac26ecb3a
commit d669bf1c59
11 changed files with 396 additions and 1 deletions
+114
View File
@@ -0,0 +1,114 @@
import {
Body,
Controller,
Delete,
Get,
HttpCode,
Param,
ParseIntPipe,
Patch,
Post,
Query,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { ScenarioService } from './scenario.service';
import { CreateScenarioDto } from './dto/create-scenario.dto';
import { UpdateScenarioDto } from './dto/update-scenario.dto';
import { CreateScenarioStepDto } from './dto/create-scenario-step.dto';
import { UpdateScenarioStepDto } from './dto/update-scenario-step.dto';
import { PaginationQueryDto } from './dto/pagination-query.dto';
@ApiTags('scenarios')
@Controller('scenarios')
export class ScenarioController {
constructor(private readonly scenarioService: ScenarioService) {}
// ── Scenarios ─────────────────────────────────────────────────────────────
@Post()
@ApiOperation({ summary: 'Create a scenario' })
@ApiResponse({ status: 201, description: 'Scenario created' })
create(@Body() dto: CreateScenarioDto) {
return this.scenarioService.create(dto);
}
@Get()
@ApiOperation({ summary: 'List all scenarios (paginated)' })
@ApiResponse({ status: 200 })
findAll(@Query() query: PaginationQueryDto) {
return this.scenarioService.findAll(query);
}
@Get(':id')
@ApiOperation({ summary: 'Get a scenario with its steps' })
@ApiResponse({ status: 200 })
@ApiResponse({ status: 404, description: 'Scenario not found' })
findOne(@Param('id', ParseIntPipe) id: number) {
return this.scenarioService.findOne(id);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a scenario' })
@ApiResponse({ status: 200 })
@ApiResponse({ status: 404, description: 'Scenario not found' })
update(@Param('id', ParseIntPipe) id: number, @Body() dto: UpdateScenarioDto) {
return this.scenarioService.update(id, dto);
}
@Delete(':id')
@HttpCode(204)
@ApiOperation({ summary: 'Delete a scenario and all its steps' })
@ApiResponse({ status: 204 })
@ApiResponse({ status: 404, description: 'Scenario not found' })
remove(@Param('id', ParseIntPipe) id: number) {
return this.scenarioService.remove(id);
}
// ── Steps ─────────────────────────────────────────────────────────────────
@Post(':id/steps')
@ApiOperation({ summary: 'Add a step to a scenario' })
@ApiResponse({ status: 201, description: 'Step created' })
@ApiResponse({ status: 404, description: 'Scenario not found' })
createStep(
@Param('id', ParseIntPipe) id: number,
@Body() dto: CreateScenarioStepDto,
) {
return this.scenarioService.createStep(id, dto);
}
@Get(':id/steps/:stepId')
@ApiOperation({ summary: 'Get a single step' })
@ApiResponse({ status: 200 })
@ApiResponse({ status: 404, description: 'Scenario or step not found' })
findStep(
@Param('id', ParseIntPipe) id: number,
@Param('stepId', ParseIntPipe) stepId: number,
) {
return this.scenarioService.findStep(id, stepId);
}
@Patch(':id/steps/:stepId')
@ApiOperation({ summary: 'Update a step' })
@ApiResponse({ status: 200 })
@ApiResponse({ status: 404, description: 'Scenario or step not found' })
updateStep(
@Param('id', ParseIntPipe) id: number,
@Param('stepId', ParseIntPipe) stepId: number,
@Body() dto: UpdateScenarioStepDto,
) {
return this.scenarioService.updateStep(id, stepId, dto);
}
@Delete(':id/steps/:stepId')
@HttpCode(204)
@ApiOperation({ summary: 'Delete a step' })
@ApiResponse({ status: 204 })
@ApiResponse({ status: 404, description: 'Scenario or step not found' })
removeStep(
@Param('id', ParseIntPipe) id: number,
@Param('stepId', ParseIntPipe) stepId: number,
) {
return this.scenarioService.removeStep(id, stepId);
}
}