feat: redesign Schattenmarkt card & detail view for explainability

- Remove abstract Konfidenz/DQ badges from match detail header
- Replace ScoreBreakdownPanel with 3-step Bewertungsherleitung for
  FUTURE_AVAILABILITY: Kriterien-Match per factor with bars, Signal-
  Abschlag (verified ERP = kein Abschlag / probabilistic = -N Punkte),
  Gesamt-Score
- Restructure FutureAvailabilityContextPanel: source section first,
  verified ERP box for LEASE_CONTRACT, remove Konfidenz row, disclaimer
  as grey footnote instead of yellow alert
- Add LEASE_EXPIRY to signal type/relevance bridge labels
- Show up to 3 match reasons with explanation on cards (was 1)
- matchCardAdapter: return top-3 positive factors as reasons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-20 12:39:12 +02:00
parent 9f391d17cb
commit d5a4862a28
5 changed files with 304 additions and 142 deletions
+1 -21
View File
@@ -45,12 +45,6 @@ function buildReasons(match: NonNullable<ReturnType<typeof useMatchDetail>['data
}))
}
function confColor(c: number) {
return c >= 0.75 ? '#1a7a4a' : c >= 0.55 ? '#d97706' : '#c0392b'
}
function dqColor(q: number) {
return q >= 0.80 ? '#1a7a4a' : q >= 0.60 ? '#d97706' : '#c0392b'
}
export default function MatchDetail() {
const { matchId } = useParams<{ matchId: string }>()
@@ -108,10 +102,6 @@ export default function MatchDetail() {
const location = city
? `${city}${property?.location?.district ? `, ${property.location.district}` : ''}`
: signal?.locationHint ?? ''
const dqScore = property?.dataQuality?.score ?? signal?.confidenceScore ?? 0.5
const confPct = Math.round(match.confidenceLevel * 100)
const dqPct = Math.round(dqScore * 100)
// Tax calculator — only shown when AI evaluated taxEnvironment
const allFactors = [...match.positiveFactors, ...(match.negativeFactors ?? [])]
const hasTaxFactor = allFactors.some(f => f.criterion === 'taxEnvironment')
@@ -223,16 +213,6 @@ export default function MatchDetail() {
{property?.assetType && (
<Chip label={property.assetType} size="small" variant="outlined" sx={{ fontSize: '0.72rem' }} />
)}
<Chip
label={`${confPct}% Konfidenz`}
size="small"
sx={{ bgcolor: confColor(match.confidenceLevel), color: 'white', fontSize: '0.72rem' }}
/>
<Chip
label={`DQ ${dqPct}%`}
size="small"
sx={{ bgcolor: dqColor(dqScore), color: 'white', fontSize: '0.72rem' }}
/>
</Box>
</Box>
@@ -343,7 +323,7 @@ export default function MatchDetail() {
{/* Sidebar */}
<Box sx={{ width: { xs: '100%', lg: 320 }, flexShrink: 0, position: { xs: 'static', lg: 'sticky' }, top: 64, display: 'flex', flexDirection: 'column', gap: 2 }}>
<ScoreBreakdownPanel match={match} taxCalculatorUrl={taxCalculatorUrl} />
<ScoreBreakdownPanel match={match} taxCalculatorUrl={taxCalculatorUrl} isFuture={isFuture} signal={signal} />
<NextActionsPanel
match={match}
onCompare={handleCompare}