Skip to content

Commit d938644

Browse files
committed
fix: rewrite dedup to use composite key (name+email+date+position)
Previous dedup was bypassed because each DB row has a unique id/token. New approach uses candidateName + candidateEmail + date + position as the composite key (case-insensitive, trimmed) to catch true duplicates. Keeps first occurrence (newest by created_at DESC ordering from DB).
1 parent 749a605 commit d938644

1 file changed

Lines changed: 17 additions & 11 deletions

File tree

dashboard/hr.html

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,20 +2893,26 @@ <h6 style="font-size:0.88rem;font-weight:700;margin-bottom:10px;display:flex;ali
28932893
};
28942894
});
28952895
// DEDUP: Remove duplicate interview records (keep first = newest by created_at)
2896-
const seen = new Set();
2896+
// Use composite key as primary dedup: candidate + date + position + round
2897+
const seenIds = new Set();
2898+
const seenKeys = new Set();
28972899
data.interviews = data.interviews.filter(int => {
2898-
// Primary key: DB id
2899-
if (int.id && seen.has('id:' + int.id)) return false;
2900-
if (int.id) seen.add('id:' + int.id);
2901-
// Secondary key: token (unique per interview)
2902-
if (int.token && seen.has('tk:' + int.token)) return false;
2903-
if (int.token) seen.add('tk:' + int.token);
2904-
// Tertiary key: composite (email + date + position)
2905-
const ck = (int.candidateEmail + '|' + int.date + '|' + int.position).toLowerCase();
2906-
if (seen.has('ck:' + ck)) return false;
2907-
seen.add('ck:' + ck);
2900+
// Skip exact same DB id (paranoia check)
2901+
if (int.id && seenIds.has(int.id)) return false;
2902+
if (int.id) seenIds.add(int.id);
2903+
// Composite key: name + email + date + position (trims whitespace)
2904+
const name = (int.candidateName || '').trim().toLowerCase();
2905+
const email = (int.candidateEmail || '').trim().toLowerCase();
2906+
const dt = (int.date || '').trim();
2907+
const pos = (int.position || '').trim().toLowerCase();
2908+
const ck = name + '|' + email + '|' + dt + '|' + pos;
2909+
if (seenKeys.has(ck)) return false;
2910+
seenKeys.add(ck);
29082911
return true;
29092912
});
2913+
if (seenKeys.size < data.interviews.length + (seenIds.size - seenKeys.size)) {
2914+
console.log('[sync] Deduped interviews: ' + seenIds.size + ' rows -> ' + data.interviews.length + ' unique');
2915+
}
29102916
});
29112917
synced++;
29122918
} else if (intRes.error) {

0 commit comments

Comments
 (0)