Files
lcbp3/backend/src/modules/migration/migration.controller.ts
T
admin 2f0d67d8b2
Build and Deploy / deploy (push) Successful in 7m11s
260317:0837 Refactor to n8n
2026-03-17 08:37:01 +07:00

174 lines
5.0 KiB
TypeScript

import {
Controller,
Post,
Body,
Headers,
UseGuards,
Get,
Param,
Query,
Res,
ParseIntPipe,
} from '@nestjs/common';
import { MigrationService } from './migration.service';
import { ImportCorrespondenceDto } from './dto/import-correspondence.dto';
import { EnqueueMigrationDto } from './dto/enqueue-migration.dto';
import { CommitBatchDto } from './dto/commit-batch.dto';
import { CreateMigrationErrorDto } from './dto/create-migration-error.dto';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import {
ApiTags,
ApiOperation,
ApiBearerAuth,
ApiHeader,
ApiQuery,
ApiParam,
} from '@nestjs/swagger';
import { MigrationQueueQueryDto } from './dto/migration-queue-query.dto';
import type { Response } from 'express';
@ApiTags('Migration')
@ApiBearerAuth()
@Controller('migration')
export class MigrationController {
constructor(private readonly migrationService: MigrationService) {}
@Post('import')
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary: 'Import generic legacy correspondence record via n8n integration',
})
@ApiHeader({
name: 'Idempotency-Key',
description:
'Unique key per document and batch to prevent duplicate inserts',
required: true,
})
async importCorrespondence(
@Body() dto: ImportCorrespondenceDto,
@Headers('idempotency-key') idempotencyKey: string,
@CurrentUser() user: any
) {
const userId = user?.id || user?.userId || 5;
return this.migrationService.importCorrespondence(
dto,
idempotencyKey,
userId
);
}
@Post('commit_batch')
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary: 'Batch approve and import migration review queue items',
})
@ApiHeader({
name: 'Idempotency-Key',
description:
'Unique key for the entire batch to prevent duplicate execution',
required: true,
})
async commitBatch(
@Body() dto: CommitBatchDto,
@Headers('idempotency-key') idempotencyKey: string,
@CurrentUser() user: any
) {
const userId = user?.id || user?.userId || 5;
return this.migrationService.commitBatch(dto, idempotencyKey, userId);
}
@Post('queue')
@UseGuards(JwtAuthGuard)
@ApiOperation({
summary: 'Enqueue a record into the staging migration review queue',
})
async enqueueRecord(@Body() dto: EnqueueMigrationDto) {
return this.migrationService.enqueueRecord(dto);
}
@Get('queue')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Get migration review queue' })
async getReviewQueue(@Query() query: MigrationQueueQueryDto) {
return this.migrationService.getReviewQueue(query);
}
@Get('queue/:id')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Get a specific queue item by ID' })
@ApiParam({ name: 'id', type: Number })
async getQueueItemById(@Param('id', ParseIntPipe) id: number) {
return this.migrationService.getQueueItemById(id);
}
@Post('errors')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Log a migration error from n8n workflow' })
async createError(@Body() dto: CreateMigrationErrorDto) {
return this.migrationService.createError(dto);
}
@Get('errors')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Get migration errors' })
@ApiQuery({ name: 'page', required: false, type: Number })
@ApiQuery({ name: 'limit', required: false, type: Number })
async getErrors(
@Query('page') page?: number,
@Query('limit') limit?: number
) {
return this.migrationService.getErrors(page, limit);
}
@Post('queue/:id/approve')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Approve and import a queued migration item' })
@ApiParam({ name: 'id', type: Number })
@ApiHeader({
name: 'Idempotency-Key',
description:
'Unique key per document and batch to prevent duplicate inserts',
required: true,
})
async approveQueueItem(
@Param('id', ParseIntPipe) id: number,
@Body() dto: ImportCorrespondenceDto,
@Headers('idempotency-key') idempotencyKey: string,
@CurrentUser() user: any
) {
const userId = user?.id || user?.userId || 5;
return this.migrationService.approveQueueItem(
id,
dto,
idempotencyKey,
userId
);
}
@Post('queue/:id/reject')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Reject a queued migration item' })
@ApiParam({ name: 'id', type: Number })
async rejectQueueItem(
@Param('id', ParseIntPipe) id: number,
@CurrentUser() user: any
) {
const userId = user?.id || user?.userId || 5;
return this.migrationService.rejectQueueItem(id, userId);
}
@Get('staging-file')
@UseGuards(JwtAuthGuard)
@ApiOperation({ summary: 'Stream a file from staging' })
@ApiQuery({ name: 'path', required: true, type: String })
async getStagingFile(@Query('path') filePath: string, @Res() res: Response) {
const stream = this.migrationService.getStagingFileStream(filePath);
res.set({
'Content-Type': 'application/pdf',
'Content-Disposition': 'inline; filename="document.pdf"',
});
stream.pipe(res);
}
}