fix: Schattenmarkt bypass source filter + bump external/maison match scores for all tiers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-05-19 23:10:41 +02:00
parent 3756675b6f
commit 0663757cde
2 changed files with 49 additions and 48 deletions
+43 -43
View File
@@ -42,10 +42,10 @@ export const mockMatches: Match[] = [
id: 'match-002',
propertyId: 'prop-004',
needId: 'need-001',
matchScore: 64,
matchStrength: MatchStrength.MODERATE,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 78, softFactorScore: 62, confidenceModifier: 0.68, dataQualityModifier: 0.55, totalScore: 64 },
matchScore: 93,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 95, softFactorScore: 91, confidenceModifier: 0.82, dataQualityModifier: 0.75, totalScore: 93 },
positiveFactors: [
{ criterion: 'Fläche', weight: 0.20, score: 88, contribution: 17.6, explanation: '1150m² liegt im erweiterten Korridor' },
{ criterion: 'Standort', weight: 0.20, score: 80, contribution: 16, explanation: 'Zürich Kreis 4 nahe bevorzugten Lagen' },
@@ -181,10 +181,10 @@ export const mockMatches: Match[] = [
id: 'match-009',
propertyId: 'prop-015',
needId: 'need-001',
matchScore: 51,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 65, softFactorScore: 53, confidenceModifier: 0.70, dataQualityModifier: 0.60, totalScore: 51 },
matchScore: 86,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 90, softFactorScore: 84, confidenceModifier: 0.76, dataQualityModifier: 0.72, totalScore: 86 },
positiveFactors: [
{ criterion: 'Fläche', weight: 0.20, score: 88, contribution: 17.6, explanation: '650m² im Zielkorridor' },
{ criterion: 'Budget', weight: 0.15, score: 90, contribution: 13.5, explanation: 'CHF 38/m² unter Maximum' },
@@ -296,10 +296,10 @@ export const mockMatches: Match[] = [
id: 'match-011',
propertyId: 'prop-016',
needId: 'need-002',
matchScore: 76,
matchStrength: MatchStrength.MODERATE,
matchScore: 93,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.APPROVED,
scoreBreakdown: { hardMatchScore: 90, softFactorScore: 74, confidenceModifier: 0.69, dataQualityModifier: 0.58, totalScore: 76 },
scoreBreakdown: { hardMatchScore: 95, softFactorScore: 92, confidenceModifier: 0.83, dataQualityModifier: 0.76, totalScore: 93 },
positiveFactors: [
{ criterion: 'Fläche', weight: 0.25, score: 92, contribution: 23, explanation: '2200m² im Zielkorridor' },
{ criterion: 'Standort', weight: 0.20, score: 78, contribution: 15.6, explanation: 'Muttenz BL gleicher Kanton, gute Lage' },
@@ -466,10 +466,10 @@ export const mockMatches: Match[] = [
id: 'match-017',
propertyId: 'prop-018',
needId: 'need-003',
matchScore: 44,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 58, softFactorScore: 46, confidenceModifier: 0.68, dataQualityModifier: 0.57, totalScore: 44 },
matchScore: 87,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 92, softFactorScore: 85, confidenceModifier: 0.78, dataQualityModifier: 0.70, totalScore: 87 },
positiveFactors: [
{ criterion: 'Budget', weight: 0.20, score: 95, contribution: 19, explanation: 'CHF 31/m² deutlich unter Maximum' },
{ criterion: 'Fläche', weight: 0.20, score: 88, contribution: 17.6, explanation: '780m² nahe am Zielkorridor' },
@@ -579,10 +579,10 @@ export const mockMatches: Match[] = [
id: 'match-021',
propertyId: 'prop-017',
needId: 'need-004',
matchScore: 79,
matchStrength: MatchStrength.MODERATE,
matchScore: 91,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 93, softFactorScore: 77, confidenceModifier: 0.71, dataQualityModifier: 0.61, totalScore: 79 },
scoreBreakdown: { hardMatchScore: 94, softFactorScore: 90, confidenceModifier: 0.81, dataQualityModifier: 0.74, totalScore: 91 },
positiveFactors: [
{ criterion: 'Standort', weight: 0.35, score: 94, contribution: 32.9, explanation: 'Zürich Löwenstrasse Innenstadtlage' },
{ criterion: 'Budget', weight: 0.15, score: 95, contribution: 14.25, explanation: 'CHF 95/m² unter Maximum' },
@@ -634,10 +634,10 @@ export const mockMatches: Match[] = [
id: 'match-023',
propertyId: 'prop-003',
needId: 'need-004',
matchScore: 44,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 58, softFactorScore: 46, confidenceModifier: 0.71, dataQualityModifier: 0.62, totalScore: 44 },
matchScore: 84,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 89, softFactorScore: 82, confidenceModifier: 0.77, dataQualityModifier: 0.69, totalScore: 84 },
positiveFactors: [
{ criterion: 'Budget', weight: 0.15, score: 95, contribution: 14.25, explanation: 'CHF 95/m² unter Maximum CHF 100/m²' },
{ criterion: 'Prestige', weight: 0.15, score: 92, contribution: 13.8, explanation: 'Berner Bahnhofstrasse Top-Prestige' },
@@ -661,10 +661,10 @@ export const mockMatches: Match[] = [
id: 'match-024',
propertyId: 'prop-021',
needId: 'need-004',
matchScore: 33,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.REJECTED,
scoreBreakdown: { hardMatchScore: 47, softFactorScore: 35, confidenceModifier: 0.70, dataQualityModifier: 0.59, totalScore: 33 },
matchScore: 72,
matchStrength: MatchStrength.MODERATE,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 81, softFactorScore: 70, confidenceModifier: 0.72, dataQualityModifier: 0.62, totalScore: 72 },
positiveFactors: [
{ criterion: 'Prestige', weight: 0.15, score: 94, contribution: 14.1, explanation: 'Rue du Rhône Genf sehr hoher Prestige-Score' },
],
@@ -827,10 +827,10 @@ export const mockMatches: Match[] = [
id: 'match-030',
propertyId: 'prop-022',
needId: 'need-005',
matchScore: 43,
matchStrength: MatchStrength.WEAK,
matchScore: 73,
matchStrength: MatchStrength.MODERATE,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 57, softFactorScore: 45, confidenceModifier: 0.69, dataQualityModifier: 0.58, totalScore: 43 },
scoreBreakdown: { hardMatchScore: 82, softFactorScore: 71, confidenceModifier: 0.71, dataQualityModifier: 0.62, totalScore: 73 },
positiveFactors: [
{ criterion: 'Budget', weight: 0.20, score: 100, contribution: 20, explanation: 'CHF 28/m² deutlich unter Maximum' },
{ criterion: 'Fläche', weight: 0.20, score: 88, contribution: 17.6, explanation: '700m² exakt an der Obergrenze' },
@@ -936,10 +936,10 @@ export const mockMatches: Match[] = [
id: 'match-034',
propertyId: 'prop-016',
needId: 'need-006',
matchScore: 50,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 64, softFactorScore: 50, confidenceModifier: 0.69, dataQualityModifier: 0.58, totalScore: 50 },
matchScore: 88,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 92, softFactorScore: 87, confidenceModifier: 0.79, dataQualityModifier: 0.73, totalScore: 88 },
positiveFactors: [
{ criterion: 'Fläche', weight: 0.30, score: 88, contribution: 26.4, explanation: '2200m² im Zielkorridor' },
{ criterion: 'Budget', weight: 0.20, score: 85, contribution: 17, explanation: 'CHF 16/m² exakt im Maximum' },
@@ -1162,10 +1162,10 @@ export const mockMatches: Match[] = [
id: 'match-042',
propertyId: 'prop-019',
needId: 'need-008',
matchScore: 47,
matchStrength: MatchStrength.WEAK,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 61, softFactorScore: 47, confidenceModifier: 0.68, dataQualityModifier: 0.56, totalScore: 47 },
matchScore: 85,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.SHORTLISTED,
scoreBreakdown: { hardMatchScore: 90, softFactorScore: 83, confidenceModifier: 0.77, dataQualityModifier: 0.71, totalScore: 85 },
positiveFactors: [
{ criterion: 'Budget', weight: 0.20, score: 95, contribution: 19, explanation: 'CHF 13/m² unter Maximum CHF 14/m²' },
],
@@ -1248,10 +1248,10 @@ export const mockMatches: Match[] = [
id: 'match-045',
propertyId: 'prop-017',
needId: 'need-009',
matchScore: 38,
matchStrength: MatchStrength.WEAK,
matchScore: 76,
matchStrength: MatchStrength.MODERATE,
status: MatchStatus.PENDING_REVIEW,
scoreBreakdown: { hardMatchScore: 52, softFactorScore: 40, confidenceModifier: 0.71, dataQualityModifier: 0.61, totalScore: 38 },
scoreBreakdown: { hardMatchScore: 85, softFactorScore: 74, confidenceModifier: 0.73, dataQualityModifier: 0.64, totalScore: 76 },
positiveFactors: [
{ criterion: 'Budget', weight: 0.15, score: 100, contribution: 15, explanation: 'CHF 95/m² unter Maximum CHF 120/m²' },
],
@@ -1278,10 +1278,10 @@ export const mockMatches: Match[] = [
id: 'match-046',
propertyId: 'prop-022',
needId: 'need-010',
matchScore: 79,
matchStrength: MatchStrength.MODERATE,
matchScore: 92,
matchStrength: MatchStrength.STRONG,
status: MatchStatus.APPROVED,
scoreBreakdown: { hardMatchScore: 93, softFactorScore: 77, confidenceModifier: 0.69, dataQualityModifier: 0.58, totalScore: 79 },
scoreBreakdown: { hardMatchScore: 95, softFactorScore: 91, confidenceModifier: 0.82, dataQualityModifier: 0.74, totalScore: 92 },
positiveFactors: [
{ criterion: 'Standort', weight: 0.28, score: 100, contribution: 28, explanation: 'St. Gallen Centrum exakter Standortwunsch' },
{ criterion: 'Budget', weight: 0.20, score: 95, contribution: 19, explanation: 'CHF 28/m² deutlich unter Maximum CHF 35/m²' },
+6 -5
View File
@@ -71,11 +71,12 @@ export default function Results() {
const { data: results = [], isLoading } = useUnifiedResults(activeNeed?.id)
const filtered = results
// Exclude VERIFIED_PORTFOLIO by default; include only when toggled on by Property Manager
.filter(r => r.resultType !== 'VERIFIED_PORTFOLIO' || showOwnProperties)
.filter(r => filterSource === 'ALL' || r.resultType === filterSource)
.filter(r => showSchattenmarkt || r.resultType !== 'FUTURE_AVAILABILITY')
const filtered = results.filter(r => {
if (r.resultType === 'VERIFIED_PORTFOLIO') return showOwnProperties
// Schattenmarkt toggle is independent of the source filter
if (r.resultType === 'FUTURE_AVAILABILITY') return showSchattenmarkt
return filterSource === 'ALL' || r.resultType === filterSource
})
const sorted = sortResults(filtered, sortBy)