feat(matching): implement origin_run_id tracking and audit tests
- Updated run-matching endpoint to create MatchingRun records - Added trigger tracking (manual vs scheduler) - Fixed saveMatchingResults to accept runId parameter - Added comprehensive audit tests (matching-runs-audit.test.js): * TC1: origin_run_id assigned correctly * TC2: Sequential runs create separate run IDs * TC3: Accepted suggestions preserve origin_run_id * TC4: Filter parameters (onlyAssigned, includeNotFound) * TC5: Manual vs scheduler trigger differentiation * TC6: Failed runs recorded in audit trail - All 6 audit tests passing
This commit is contained in:
@@ -1144,25 +1144,65 @@ router.post('/:slug/run-matching', authenticate, async (req, res, next) => {
|
||||
// TODO: In production, add admin check or deadline validation
|
||||
// For now, allow anyone to run matching for testing
|
||||
|
||||
// Run matching algorithm
|
||||
const suggestions = await matchingService.runMatching(event.id);
|
||||
const startedAt = new Date();
|
||||
let runRow = null;
|
||||
|
||||
// Save results
|
||||
const count = await matchingService.saveMatchingResults(event.id, suggestions);
|
||||
try {
|
||||
// Create run audit row
|
||||
runRow = await prisma.matchingRun.create({
|
||||
data: {
|
||||
eventId: event.id,
|
||||
trigger: 'manual',
|
||||
status: 'running',
|
||||
startedAt,
|
||||
},
|
||||
});
|
||||
|
||||
// Get statistics
|
||||
const notFoundCount = suggestions.filter(s => s.status === SUGGESTION_STATUS.NOT_FOUND).length;
|
||||
const matchedCount = suggestions.filter(s => s.status === SUGGESTION_STATUS.PENDING).length;
|
||||
// Run matching algorithm
|
||||
const suggestions = await matchingService.runMatching(event.id);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
totalHeats: suggestions.length,
|
||||
matched: matchedCount,
|
||||
notFound: notFoundCount,
|
||||
runAt: new Date(),
|
||||
},
|
||||
});
|
||||
// Save results with runId for audit trail
|
||||
const count = await matchingService.saveMatchingResults(event.id, suggestions, runRow.id);
|
||||
|
||||
// Get statistics
|
||||
const notFoundCount = suggestions.filter(s => s.status === SUGGESTION_STATUS.NOT_FOUND).length;
|
||||
const matchedCount = suggestions.filter(s => s.status === SUGGESTION_STATUS.PENDING).length;
|
||||
|
||||
// Update run audit row with success
|
||||
await prisma.matchingRun.update({
|
||||
where: { id: runRow.id },
|
||||
data: {
|
||||
status: 'success',
|
||||
endedAt: new Date(),
|
||||
matchedCount,
|
||||
notFoundCount,
|
||||
},
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
totalHeats: suggestions.length,
|
||||
matched: matchedCount,
|
||||
notFound: notFoundCount,
|
||||
runAt: new Date(),
|
||||
runId: runRow.id,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
// Update run audit row with failure
|
||||
if (runRow) {
|
||||
await prisma.matchingRun.update({
|
||||
where: { id: runRow.id },
|
||||
data: {
|
||||
status: 'failed',
|
||||
endedAt: new Date(),
|
||||
errorMessage: error.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user