개인정보-컴플라이언스-웹애플리케이션 (수정사항 2)
백엔드 코드중에 슈퍼유저의 기능중에 전문가와 시스템을 매칭해주는 코드가있었는데 그쪽에서 문제가 생겼습니다.
수정전 코드
const matchExpertsToSystem = async (req, res) => {
const { systemId, expertIds } = req.body;
if (!systemId || !Array.isArray(expertIds) || expertIds.length === 0) {
return res.status(400).json({
resultCode: "F-1",
msg: "시스템 ID와 전문가 ID 목록을 제공해야 합니다.",
});
}
try {
// 기존 매칭 데이터 삭제
await pool.query("DELETE FROM assignment WHERE systems_id = ?", [systemId]);
// INSERT 쿼리
const values = expertIds.map((expertId) => [expertId, systemId, false]); // feedback_status 기본값 false 추가
const query = `
INSERT INTO assignment (expert_id, systems_id, feedback_status)
VALUES ?
`;
await pool.query(query, [values]);
res.status(200).json({
resultCode: "S-1",
msg: "매칭이 성공적으로 완료되었습니다.",
});
} catch (error) {
console.error("❌ [MATCH EXPERTS TO SYSTEM] 매칭 실패:", error.message);
res.status(500).json({
resultCode: "F-1",
msg: "매칭 중 오류가 발생했습니다.",
error: error.message,
});
}
};
기존에는
await pool.query("DELETE FROM assignment WHERE systems_id = ?", [systemId]);
🚨 기존 코드에서 기존 매칭을 삭제하는 이유
새로운 전문가 목록(expertIds)을 그대로 덮어쓰기 위한 목적
기존 전문가 매칭이 있든 없든 무조건 삭제 후 새로운 데이터 삽입하는 방식입니다.
즉, 기존 전문가가 그대로 유지될 필요 없이, 요청받은 전문가 목록을 그대로 적용하려는 것 입니다.
삭제하지 않고 INSERT 하면 중복 데이터가 발생할 수 있습니다.
assignment 테이블에는 전문가(expert_id), 시스템(systems_id) 간 중복을 방지하는 제약 조건이 없을 수도 있습니다.
따라서 기존 데이터를 삭제하지 않으면, 같은 전문가가 동일한 시스템에 여러 번 배정되는 문제가 발생할 가능성이 있습니다.
기존 코드가 ‘현재 매칭 데이터를 완전히 덮어씌우는’ 방식이기 때문입니다
DELETE 없이 INSERT만 하면, 기존 데이터와 새로운 데이터가 혼합될 수도 있습니다.
기존 전문가에서 빠진 경우(즉, 삭제가 필요한 전문가가 있는 경우)를 처리할 수 없습니다.
❌ 문제점: 모든 매칭을 삭제하면 비효율적
하지만 이 방식에는 여러 가지 문제점이 있습니다.
1. 불필요한 삭제 발생
만약 기존 전문가가 새 요청과 완전히 동일하다면, 삭제 후 동일한 데이터를 다시 삽입하는 비효율적인 과정이 발생합니다.
2. 기존 데이터(feedback_status 등) 손실
assignment 테이블에는 feedback_status 같은 상태가 포함될 수 있습니다.
기존 전문가가 다시 배정될 경우, 해당 전문가의 피드백 상태가 초기화될 위험이 있습니다.
3. 새로운 전문가만 추가하는 방식이 더 낫습니다
기존 전문가를 유지하고, 새로운 전문가만 추가하는 것이 더 좋은 방식입니다.
수정한 코드
const matchExpertsToSystem = async (req, res) => {
const { systemId, expertIds } = req.body;
if (!systemId || !Array.isArray(expertIds) || expertIds.length === 0) {
return res.status(400).json({
resultCode: "F-1",
msg: "시스템 ID와 전문가 ID 목록을 제공해야 합니다.",
});
}
try {
// ✅ 기존에 배정된 전문가 조회 (중복 체크용)
const checkQuery = `
SELECT expert_id FROM assignment WHERE systems_id = ?;
`;
const [existingAssignments] = await pool.query(checkQuery, [systemId]);
// 기존에 배정된 전문가 ID 목록
const existingExpertIds = new Set(existingAssignments.map(row => row.expert_id));
// ✅ 새로 추가할 전문가만 필터링 (중복 제거)
const newExpertIds = expertIds.filter(expertId => !existingExpertIds.has(expertId));
if (newExpertIds.length === 0) {
return res.status(409).json({
resultCode: "F-2",
msg: "모든 전문가가 이미 배정되어 있습니다.",
});
}
// ✅ 중복되지 않은 전문가만 새로 추가
const values = newExpertIds.map(expertId => [expertId, systemId, false]);
const insertQuery = `
INSERT INTO assignment (expert_id, systems_id, feedback_status)
VALUES ?;
`;
await pool.query(insertQuery, [values]);
res.status(200).json({
resultCode: "S-1",
msg: "새로운 전문가 매칭이 성공적으로 완료되었습니다.",
});
} catch (error) {
console.error("❌ [MATCH EXPERTS TO SYSTEM] 매칭 실패:", error.message);
res.status(500).json({
resultCode: "F-1",
msg: "매칭 중 오류가 발생했습니다.",
error: error.message,
});
}
};
🛠 주요 수정 사항
1. 기존 배정된 전문가 조회 추가 (checkQuery)
기존에 배정된 전문가 목록을 먼저 가져와서 중복 체크를 수행하도록 변경합니다.
중복된 전문가를 다시 추가하지 않도록 방지합니다.
2. 이미 배정된 전문가 필터링 (newExpertIds)
기존 expertIds에서 이미 배정된 전문가를 제거하여 새로운 전문가만 추가하도록 수정합니다.
이를 위해 Set을 사용하여 existingExpertIds 목록을 생성하고, filter()를 적용합니다.
3. 중복된 경우 409 Conflict 응답 추가
기존 코드에서는 새로운 전문가가 없을 때도 요청을 진행했는데, 이를 방지합니다.
모든 전문가가 이미 배정된 경우, 409 Conflict 응답을 반환하고 요청을 중단합니다.
4. SQL INSERT 문에 중복을 제거한 데이터만 삽입
newExpertIds 배열을 이용하여 새로운 전문가만 추가합니다.
기존 방식은 중복이 포함될 가능성이 있었으나, 이를 해결합니다.
📌 기존 코드 vs 수정 코드 비교
기능기존 코드수정 코드
기존 배정된 전문가 확인 | ❌ 없음 | ✅ SELECT expert_id FROM assignment WHERE systems_id = ?; |
이미 배정된 전문가 처리 | ❌ 중복 삽입 가능 | ✅ 기존 전문가 제거 후 새로운 전문가만 추가 |
모든 전문가가 이미 배정된 경우 | ❌ 무조건 INSERT 시도 | ✅ 409 Conflict 응답 반환 |
불필요한 DELETE 제거 | ❌ 기존 매칭 삭제 | ✅ 기존 데이터 유지 |