M3: implement Data Quality Workbench

Five rule scanners (duplicate customers, missing fields, odometer regression, booking overlap, status conflict) run automatically after seed and via an explicit scan endpoint. Issue defer/reject/merge-customers endpoints with transactional customer merge (booking rewiring, tombstone, audit). Data Quality nav + workbench UI with two-column duplicate comparison and inline (non-native) confirm. Dashboard attention items now link to issues. 35 backend tests passing, ruff clean. Fixed a real false-positive bug in odometer-regression detection found through iteration on seed data, and two TS narrowing errors. Verified end-to-end via browser: S2 merge and S4 overlap scenarios.
This commit is contained in:
NuklearRabbit
2026-08-01 22:11:06 +02:00
parent 0091c57c7f
commit a7cbeaae3b
17 changed files with 1127 additions and 5 deletions
+32
View File
@@ -188,6 +188,38 @@ a { color: #1f5c8f; }
.return-form button:disabled { opacity: 0.6; cursor: not-allowed; }
.return-result .error { margin-top: 12px; }
.duplicate-compare fieldset {
border: 1px solid #dce3eb; border-radius: 10px; padding: 12px 16px; margin: 12px 0;
}
.duplicate-compare legend { font-weight: 700; color: #375065; padding: 0 6px; }
.duplicate-compare fieldset label { margin-right: 20px; }
.compare-table th, .compare-table td { vertical-align: top; }
.compare-table label { display: inline-flex; align-items: center; gap: 6px; font-weight: 400; }
.duplicate-compare > button {
padding: 12px 20px; border-radius: 10px; border: none;
background: #14324f; color: white; font-weight: 700; cursor: pointer; margin-top: 12px;
}
.confirm-bar {
margin-top: 12px; padding: 14px; border-radius: 10px;
background: #fdf1de; border: 1px solid #f0d29e;
}
.confirm-bar p { margin: 0 0 10px; font-weight: 600; color: #8a5a10; }
.confirm-bar button {
padding: 10px 16px; border-radius: 8px; border: none; font-weight: 700; cursor: pointer; margin-right: 8px;
}
.confirm-bar button:first-of-type { background: #9a2530; color: white; }
.confirm-bar button:last-of-type { background: white; border: 1px solid #cfd8e2; }
.evidence-block {
background: #f6f8fb; border: 1px solid #dce3eb; border-radius: 10px;
padding: 12px; overflow-x: auto; font-size: 0.85rem;
}
.resolution-actions { display: flex; gap: 10px; margin-top: 12px; }
.resolution-actions button {
padding: 10px 18px; border-radius: 8px; border: 1px solid #cfd8e2;
background: white; font-weight: 700; cursor: pointer;
}
@media (max-width: 700px) {
.app-header { flex-direction: column; align-items: flex-start; }
.user-badge { margin-left: 0; }