260326:0842 Fixing Naming convention missunderstand #0
CI / CD Pipeline / build (push) Successful in 15m38s
CI / CD Pipeline / deploy (push) Failing after 1m26s

This commit is contained in:
admin
2026-03-26 08:42:54 +07:00
parent d36d4b0bf4
commit c1eb79511a
2 changed files with 62 additions and 66 deletions
@@ -63,10 +63,7 @@ export class VirtualColumnService {
tableName: string, tableName: string,
config: VirtualColumnConfig config: VirtualColumnConfig
) { ) {
const hasColumn = await queryRunner.hasColumn( const hasColumn = await queryRunner.hasColumn(tableName, config.columnName);
tableName,
config.column_name
);
if (!hasColumn) { if (!hasColumn) {
const sql = this.generateAddColumnSql(tableName, config); const sql = this.generateAddColumnSql(tableName, config);
@@ -75,7 +72,7 @@ export class VirtualColumnService {
} else { } else {
// TODO: (Advance) ถ้ามี Column แล้ว แต่ Definition เปลี่ยน อาจต้อง ALTER MODIFY // TODO: (Advance) ถ้ามี Column แล้ว แต่ Definition เปลี่ยน อาจต้อง ALTER MODIFY
this.logger.debug( this.logger.debug(
`Column '${config.column_name}' already exists in '${tableName}'.` `Column '${config.columnName}' already exists in '${tableName}'.`
); );
} }
} }
@@ -88,7 +85,7 @@ export class VirtualColumnService {
tableName: string, tableName: string,
config: VirtualColumnConfig config: VirtualColumnConfig
) { ) {
const indexName = `idx_${tableName}_${config.column_name}`; const indexName = `idx_${tableName}_${config.columnName}`;
// ตรวจสอบว่า Index มีอยู่จริงไหม (Query จาก information_schema เพื่อความชัวร์) // ตรวจสอบว่า Index มีอยู่จริงไหม (Query จาก information_schema เพื่อความชัวร์)
const checkIndexSql = ` const checkIndexSql = `
@@ -104,7 +101,7 @@ export class VirtualColumnService {
])) as { count: number }[]; ])) as { count: number }[];
if (result[0]?.count === 0) { if (result[0]?.count === 0) {
const sql = `CREATE ${config.index_type === 'UNIQUE' ? 'UNIQUE' : ''} INDEX ${indexName} ON ${tableName} (${config.column_name})`; const sql = `CREATE ${config.indexType === 'UNIQUE' ? 'UNIQUE' : ''} INDEX ${indexName} ON ${tableName} (${config.columnName})`;
this.logger.log(`Creating Index: ${sql}`); this.logger.log(`Creating Index: ${sql}`);
await queryRunner.query(sql); await queryRunner.query(sql);
} }
@@ -118,16 +115,16 @@ export class VirtualColumnService {
tableName: string, tableName: string,
config: VirtualColumnConfig config: VirtualColumnConfig
): string { ): string {
const dbType = this.mapDataTypeToSql(config.data_type); const dbType = this.mapDataTypeToSql(config.dataType);
// JSON_UNQUOTE(JSON_EXTRACT(details, '$.path')) // JSON_UNQUOTE(JSON_EXTRACT(details, '$.path'))
// ใช้ 'details' เป็นชื่อ column JSON หลัก (ต้องตรงกับ Database Schema ที่ออกแบบไว้) // ใช้ 'details' เป็นชื่อ column JSON หลัก (ต้องตรงกับ Database Schema ที่ออกแบบไว้)
const expression = `JSON_UNQUOTE(JSON_EXTRACT(details, '${config.json_path}'))`; const expression = `JSON_UNQUOTE(JSON_EXTRACT(details, '${config.jsonPath}'))`;
// Handle Type Casting inside expression if needed, // Handle Type Casting inside expression if needed,
// but usually MariaDB handles string return from JSON_EXTRACT. // but usually MariaDB handles string return from JSON_EXTRACT.
// For INT/DATE, virtual column type definition enforces it. // For INT/DATE, virtual column type definition enforces it.
return `ALTER TABLE ${tableName} ADD COLUMN ${config.column_name} ${dbType} GENERATED ALWAYS AS (${expression}) VIRTUAL`; return `ALTER TABLE ${tableName} ADD COLUMN ${config.columnName} ${dbType} GENERATED ALWAYS AS (${expression}) VIRTUAL`;
} }
private mapDataTypeToSql(type: string): string { private mapDataTypeToSql(type: string): string {
@@ -136,11 +136,11 @@ export class MigrationService {
// We now use project_id from n8n (instead of hardcoding LCBP3) // We now use project_id from n8n (instead of hardcoding LCBP3)
const project = await this.projectRepo.findOne({ const project = await this.projectRepo.findOne({
where: { id: dto.project_id }, where: { id: dto.projectId },
}); });
if (!project) { if (!project) {
throw new BadRequestException( throw new BadRequestException(
`Project ID ${dto.project_id} not found in database` `Project ID ${dto.projectId} not found in database`
); );
} }
@@ -154,18 +154,18 @@ export class MigrationService {
// 3. Find or Create Correspondence // 3. Find or Create Correspondence
let correspondence = await queryRunner.manager.findOne(Correspondence, { let correspondence = await queryRunner.manager.findOne(Correspondence, {
where: { where: {
correspondenceNumber: dto.document_number, correspondenceNumber: dto.documentNumber,
projectId: project.id, projectId: project.id,
}, },
}); });
if (!correspondence) { if (!correspondence) {
correspondence = queryRunner.manager.create(Correspondence, { correspondence = queryRunner.manager.create(Correspondence, {
correspondenceNumber: dto.document_number, correspondenceNumber: dto.documentNumber,
correspondenceTypeId: typeId, correspondenceTypeId: typeId,
projectId: project.id, projectId: project.id,
disciplineId: dto.discipline_id || undefined, disciplineId: dto.disciplineId || undefined,
originatorId: dto.sender_id || undefined, // Set explicitly from DTO originatorId: dto.senderId || undefined, // Set explicitly from DTO
isInternal: false, isInternal: false,
createdBy: userId, createdBy: userId,
}); });
@@ -187,12 +187,12 @@ export class MigrationService {
} else { } else {
// Update values if missing // Update values if missing
let hasChanges = false; let hasChanges = false;
if (dto.discipline_id && !correspondence.disciplineId) { if (dto.disciplineId && !correspondence.disciplineId) {
correspondence.disciplineId = dto.discipline_id; correspondence.disciplineId = dto.disciplineId;
hasChanges = true; hasChanges = true;
} }
if (dto.sender_id && !correspondence.originatorId) { if (dto.senderId && !correspondence.originatorId) {
correspondence.originatorId = dto.sender_id; correspondence.originatorId = dto.senderId;
hasChanges = true; hasChanges = true;
} }
if (hasChanges) { if (hasChanges) {
@@ -202,8 +202,8 @@ export class MigrationService {
// 4. File Handling // 4. File Handling
let attachmentId: number | null = null; let attachmentId: number | null = null;
if (dto.temp_attachment_id) { if (dto.tempAttachmentId) {
attachmentId = dto.temp_attachment_id; attachmentId = dto.tempAttachmentId;
try { try {
// Mark attachment as permanent // Mark attachment as permanent
await queryRunner.manager.update( await queryRunner.manager.update(
@@ -218,10 +218,10 @@ export class MigrationService {
`Failed to update temp_file [id:${attachmentId}]: ${errMsg}` `Failed to update temp_file [id:${attachmentId}]: ${errMsg}`
); );
} }
} else if (dto.source_file_path) { } else if (dto.sourceFilePath) {
try { try {
const attachment = await this.fileStorageService.importStagingFile( const attachment = await this.fileStorageService.importStagingFile(
dto.source_file_path, dto.sourceFilePath,
userId, userId,
{ documentType: dto.category } { documentType: dto.category }
); );
@@ -231,7 +231,7 @@ export class MigrationService {
fileError instanceof Error ? fileError.message : String(fileError); fileError instanceof Error ? fileError.message : String(fileError);
this.logger.warn( this.logger.warn(
`Failed to import file for [${dto.document_number}], continuing without attachment: ${errMsg}` `Failed to import file for [${dto.documentNumber}], continuing without attachment: ${errMsg}`
); );
} }
} }
@@ -268,14 +268,14 @@ export class MigrationService {
subject: dto.subject, subject: dto.subject,
description: 'Migrated from legacy system via Auto Ingest', description: 'Migrated from legacy system via Auto Ingest',
body: dto.body || undefined, body: dto.body || undefined,
documentDate: parseDateStr(dto.document_date || dto.issued_date), documentDate: parseDateStr(dto.documentDate || dto.issuedDate),
issuedDate: parseDateStr(dto.issued_date), issuedDate: parseDateStr(dto.issuedDate),
receivedDate: parseDateStr(dto.received_date), receivedDate: parseDateStr(dto.receivedDate),
details: { details: {
...dto.details, ...dto.details,
ai_confidence: dto.ai_confidence, ai_confidence: dto.aiConfidence,
ai_issues: dto.ai_issues as unknown, ai_issues: dto.aiIssues as unknown,
source_file_path: dto.source_file_path, source_file_path: dto.sourceFilePath,
attachment_id: attachmentId, attachment_id: attachmentId,
}, },
schemaVersion: 1, schemaVersion: 1,
@@ -323,9 +323,9 @@ export class MigrationService {
if (typeof tagItem === 'string') { if (typeof tagItem === 'string') {
tagName = tagItem; tagName = tagItem;
} else if (tagItem && typeof tagItem === 'object') { } else if (tagItem && typeof tagItem === 'object') {
const tObj = tagItem as { tag_name?: unknown }; const tObj = tagItem as { tagName?: unknown };
if (typeof tObj.tag_name === 'string') { if (typeof tObj.tagName === 'string') {
tagName = tObj.tag_name; tagName = tObj.tagName;
} }
} }
@@ -360,8 +360,8 @@ export class MigrationService {
// 6. Track Transaction // 6. Track Transaction
const transaction = queryRunner.manager.create(ImportTransaction, { const transaction = queryRunner.manager.create(ImportTransaction, {
idempotencyKey, idempotencyKey,
documentNumber: dto.document_number, documentNumber: dto.documentNumber,
batchId: dto.batch_id, batchId: dto.batchId,
statusCode: 201, statusCode: 201,
}); });
await queryRunner.manager.save(transaction); await queryRunner.manager.save(transaction);
@@ -369,7 +369,7 @@ export class MigrationService {
await queryRunner.commitTransaction(); await queryRunner.commitTransaction();
this.logger.log( this.logger.log(
`Ingested document [${dto.document_number}] successfully (Batch: ${dto.batch_id})` `Ingested document [${dto.documentNumber}] successfully (Batch: ${dto.batchId})`
); );
return { return {
@@ -385,14 +385,14 @@ export class MigrationService {
const errorStack = error instanceof Error ? error.stack : undefined; const errorStack = error instanceof Error ? error.stack : undefined;
this.logger.error( this.logger.error(
`Import failed for document [${dto.document_number}]: ${errorMessage}`, `Import failed for document [${dto.documentNumber}]: ${errorMessage}`,
errorStack errorStack
); );
const failedTransaction = this.importTransactionRepo.create({ const failedTransaction = this.importTransactionRepo.create({
idempotencyKey, idempotencyKey,
documentNumber: dto.document_number, documentNumber: dto.documentNumber,
batchId: dto.batch_id, batchId: dto.batchId,
statusCode: 500, statusCode: 500,
}); });
await this.importTransactionRepo.save(failedTransaction).catch(() => {}); await this.importTransactionRepo.save(failedTransaction).catch(() => {});
@@ -406,14 +406,14 @@ export class MigrationService {
} }
async enqueueRecord(dto: EnqueueMigrationDto) { async enqueueRecord(dto: EnqueueMigrationDto) {
if (!dto.document_number) { if (!dto.documentNumber) {
throw new BadRequestException('document_number is required'); throw new BadRequestException('documentNumber is required');
} }
// Determine status based on confidence policy in ADR-017 // Determine status based on confidence policy in ADR-017
let autoStatus = MigrationReviewStatus.PENDING; let autoStatus = MigrationReviewStatus.PENDING;
if ( if (
dto.is_valid === false || dto.isValid === false ||
(dto.confidence != null && dto.confidence < 0.6) (dto.confidence != null && dto.confidence < 0.6)
) { ) {
autoStatus = MigrationReviewStatus.REJECTED; autoStatus = MigrationReviewStatus.REJECTED;
@@ -421,43 +421,42 @@ export class MigrationService {
// Upsert or create new queue item // Upsert or create new queue item
let queueItem = await this.reviewQueueRepo.findOne({ let queueItem = await this.reviewQueueRepo.findOne({
where: { documentNumber: dto.document_number }, where: { documentNumber: dto.documentNumber },
}); });
if (!queueItem) { if (!queueItem) {
queueItem = this.reviewQueueRepo.create({ queueItem = this.reviewQueueRepo.create({
documentNumber: dto.document_number, documentNumber: dto.documentNumber,
}); });
} }
queueItem.subject = dto.subject; queueItem.subject = dto.subject;
queueItem.originalSubject = dto.original_subject; queueItem.originalSubject = dto.originalSubject;
queueItem.body = dto.body; queueItem.body = dto.body;
queueItem.aiSuggestedCategory = dto.category; queueItem.aiSuggestedCategory = dto.category;
queueItem.aiConfidence = dto.confidence; queueItem.aiIssues = dto.aiIssues;
queueItem.aiIssues = dto.ai_issues; queueItem.projectId = dto.projectId;
queueItem.projectId = dto.project_id; queueItem.senderOrganizationId = dto.senderOrgId;
queueItem.senderOrganizationId = dto.sender_org_id; queueItem.receiverOrganizationId = dto.receiverOrgId;
queueItem.receiverOrganizationId = dto.receiver_org_id;
queueItem.remarks = dto.remarks; queueItem.remarks = dto.remarks;
queueItem.aiSummary = dto.ai_summary; queueItem.aiSummary = dto.aiSummary;
queueItem.extractedTags = dto.extracted_tags; queueItem.extractedTags = dto.extractedTags;
queueItem.tempAttachmentId = dto.temp_attachment_id; queueItem.tempAttachmentId = dto.tempAttachmentId;
queueItem.status = autoStatus; queueItem.status = autoStatus;
if (dto.issued_date) { if (dto.issuedDate) {
const parsed = new Date(dto.issued_date); const parsed = new Date(dto.issuedDate);
if (!isNaN(parsed.getTime())) queueItem.issuedDate = parsed; if (!isNaN(parsed.getTime())) queueItem.issuedDate = parsed;
} }
if (dto.received_date) { if (dto.receivedDate) {
const parsed = new Date(dto.received_date); const parsed = new Date(dto.receivedDate);
if (!isNaN(parsed.getTime())) queueItem.receivedDate = parsed; if (!isNaN(parsed.getTime())) queueItem.receivedDate = parsed;
} }
await this.reviewQueueRepo.save(queueItem); await this.reviewQueueRepo.save(queueItem);
this.logger.log( this.logger.log(
`Enqueued document [${dto.document_number}] to staging queue with status [${autoStatus}]` `Enqueued document [${dto.documentNumber}] to staging queue with status [${autoStatus}]`
); );
return { return {
@@ -500,15 +499,15 @@ export class MigrationService {
async createError(dto: CreateMigrationErrorDto) { async createError(dto: CreateMigrationErrorDto) {
const error = this.errorRepo.create({ const error = this.errorRepo.create({
batchId: dto.batch_id, batchId: dto.batchId,
documentNumber: dto.document_number, documentNumber: dto.documentNumber,
errorType: dto.error_type, errorType: dto.errorType,
errorMessage: dto.error_message, errorMessage: dto.errorMessage,
rawAiResponse: dto.raw_ai_response, rawAiResponse: dto.rawAiResponse,
}); });
const saved = await this.errorRepo.save(error); const saved = await this.errorRepo.save(error);
this.logger.warn( this.logger.warn(
`Migration error logged [${dto.error_type}] for doc [${dto.document_number}] batch [${dto.batch_id}]` `Migration error logged [${dto.errorType}] for doc [${dto.documentNumber}] batch [${dto.batchId}]`
); );
return { message: 'Error logged', id: saved.id }; return { message: 'Error logged', id: saved.id };
} }
@@ -581,7 +580,7 @@ export class MigrationService {
const subKey = `${idempotencyKey}_${item.queueId}`; const subKey = `${idempotencyKey}_${item.queueId}`;
// Force batchId on the item dto // Force batchId on the item dto
item.dto.batch_id = dto.batchId; item.dto.batchId = dto.batchId;
try { try {
const result = await this.approveQueueItem( const result = await this.approveQueueItem(