feat: Reale Jahresbelastung, must-have fixes, fitOut data coverage

Reale Jahresbelastung (Change 6):
- FitOutCostPanel zeigt Jahresmiete + amortisierte Ausbaukosten für alle fitOut-Werte
- FULL/PREMIUM: Ausbau CHF 0 (bezugsfertig), SHELL/BASIC: CRB/BKP-Richtwerte amortisiert über 5 J.
- Match-Card-Chip zeigt geschätzte Investition (orange wenn >100k)
- FitOutInvestment-Typ + calcFitOutInvestment() in fitOutUtils.ts
- BackendAIService + MockAIService mit generateFitOutAdvice (IAIService-Interface)

Must-have Kriterien (Nicht prüfbar Fix):
- ÖV-Anbindung: Minutengrenze aus Freitext extrahiert, gegen publicTransportMinutes geprüft
- Mindestfläche: m²-Wert aus Freitext extrahiert, gegen areaSqm geprüft
- Ausbaugrad: neues Keyword-Rule für FULL/PREMIUM

fitOut-Datenpflege:
- fitOut-Werte zu 32 fehlenden Properties ergänzt (Logistik=SHELL, Standard=BASIC, Modern=FULL)
- MAB-Werte (200/150/250 CHF/m²) zu 3 BASIC-Objekten hinzugefügt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-06-06 20:09:55 +02:00
parent a825672197
commit b2530f9e20
40 changed files with 1755 additions and 733 deletions
+35 -13
View File
@@ -95,7 +95,7 @@ export const mockProperties: Property[] = [
parkingSpots: 30,
publicTransportMinutes: 12,
},
hardFacts: { floor: 0, parking: 30, loadingDocksCount: 2, ceilingHeightM: 7.5, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 30, loadingDocksCount: 2, ceilingHeightM: 7.5, isBarrierFree: true },
floorLevel: 0,
expansionPotentialSqm: 800,
contractDurationMonths: 36,
@@ -153,6 +153,7 @@ export const mockProperties: Property[] = [
parkingSpots: 8,
publicTransportMinutes: 5,
},
hardFacts: { fitOut: 'BASIC' },
floorLevel: 2,
expansionPotentialSqm: 200,
contractDurationMonths: 48,
@@ -212,6 +213,7 @@ export const mockProperties: Property[] = [
parkingSpots: 14,
publicTransportMinutes: 8,
},
hardFacts: { fitOut: 'FULL' },
floorLevel: 4,
contractDurationMonths: 48,
ancillaryCosts: 4.5,
@@ -268,7 +270,7 @@ export const mockProperties: Property[] = [
parkingSpots: 25,
publicTransportMinutes: 14,
},
hardFacts: { floor: 0, parking: 25, loadingDocksCount: 4, ceilingHeightM: 8, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 25, loadingDocksCount: 4, ceilingHeightM: 8, isBarrierFree: true },
floorLevel: 0,
expansionPotentialSqm: 600,
contractDurationMonths: 60,
@@ -380,6 +382,7 @@ export const mockProperties: Property[] = [
parkingSpots: 40,
publicTransportMinutes: 18,
},
hardFacts: { fitOut: 'SHELL' },
floorLevel: 0,
expansionPotentialSqm: 1200,
contractDurationMonths: 120,
@@ -437,6 +440,7 @@ export const mockProperties: Property[] = [
parkingSpots: 6,
publicTransportMinutes: 6,
},
hardFacts: { fitOut: 'FULL' },
floorLevel: 5,
contractDurationMonths: 36,
ancillaryCosts: 6.0,
@@ -495,6 +499,7 @@ export const mockProperties: Property[] = [
parkingSpots: 18,
publicTransportMinutes: 7,
},
hardFacts: { fitOut: 'BASIC' },
floorLevel: 1,
contractDurationMonths: 48,
ancillaryCosts: 5.0,
@@ -551,6 +556,7 @@ export const mockProperties: Property[] = [
parkingSpots: 45,
publicTransportMinutes: 16,
},
hardFacts: { fitOut: 'SHELL' },
floorLevel: 0,
expansionPotentialSqm: 1500,
contractDurationMonths: 60,
@@ -889,7 +895,7 @@ export const mockProperties: Property[] = [
parkingSpots: 4,
publicTransportMinutes: 6,
},
hardFacts: { floor: 1, parking: 4, fitOut: 'BASIC', ceilingHeightM: 3.2 },
hardFacts: { floor: 1, parking: 4, fitOut: 'BASIC', ceilingHeightM: 3.2, mieterausbaubeitragPerSqm: 200 },
floorLevel: 1,
expansionPotentialSqm: 90,
contractDurationMonths: 84,
@@ -1048,7 +1054,7 @@ export const mockProperties: Property[] = [
parkingSpots: 4,
publicTransportMinutes: 7,
},
hardFacts: { floor: 1, parking: 4, fitOut: 'BASIC', ceilingHeightM: 2.7 },
hardFacts: { floor: 1, parking: 4, fitOut: 'BASIC', ceilingHeightM: 2.7, mieterausbaubeitragPerSqm: 150 },
floorLevel: 1,
expansionPotentialSqm: 80,
contractDurationMonths: 84,
@@ -1112,6 +1118,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BE-EXT-003',
description: 'Attraktive Ladenfläche an der Bahnhofstrasse Bern, direkt beim Hauptbahnhof. EG, sehr hohe Laufkundschaft, maximale Visibilität. Ideal für bekannte Handelsmarken oder Dienstleister mit direktem Kundenkontakt.',
hardFacts: { fitOut: 'FULL' },
units: [
{ id: 'unit-003-1', propertyId: 'prop-003', floorLevel: 0, areaSqm: 320, available: true, rentPricePerSqm: 1140 },
],
@@ -1149,6 +1156,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'ZH-EXT-004',
description: 'Grosszügige Gewerbefläche an der Europaallee, Zürich Kreis 4, direkt beim Hauptbahnhof. Modernes Gebäude mit flexibler Aufteilung. Hervorragende ÖV-Anbindung und erstklassige Lage. Geeignet als Büro, Showroom oder gemischte Nutzung.',
hardFacts: { fitOut: 'FULL' },
units: [
{ id: 'unit-004-1', propertyId: 'prop-004', floorLevel: 2, areaSqm: 1150, available: true, rentPricePerSqm: 624 },
],
@@ -1193,6 +1201,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'LU-MW-015',
description: 'Helle Bürofläche am Kasernenplatz Luzern, im Herzen der Innenstadt. Das 3. Obergeschoss bietet eine grosszügige, flexible Raumaufteilung mit natürlichem Licht von drei Seiten. ÖV-Verbindungen in unmittelbarer Nähe (Bahnhof Luzern, 5 Minuten zu Fuss). Ideal für professionelle Dienstleister.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-015-1', propertyId: 'prop-015', floorLevel: 3, areaSqm: 650, available: true, rentPricePerSqm: 456 },
],
@@ -1236,6 +1245,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BL-MW-016',
description: 'Grosszügige Lagerhalle an der Rheinfelderstrasse, direkt im Industriegebiet Muttenz. Ebenerdige Anlieferung mit breitem Tor, 35 Aussenparkplätze. Anbindung A2/A3 unter 5 Minuten. Ideal für Lagerung, Distribution und Leichtindustrie.',
hardFacts: { fitOut: 'SHELL' },
units: [
{ id: 'unit-016-1', propertyId: 'prop-016', floorLevel: 0, unitLabel: 'Lagerhalle', areaSqm: 2200, available: true, rentPricePerSqm: 192 },
],
@@ -1280,6 +1290,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'ZH-EXT-017',
description: 'Erstklassige Ladenfläche an der Löwenstrasse im Zürcher Hauptbahnhof-Umfeld. EG, direkt an der Fussgängerzone mit sehr hoher Frequenz durch Pendler und Touristen. Schaufensterfront auf zwei Seiten.',
hardFacts: { fitOut: 'FULL' },
units: [
{ id: 'unit-017-1', propertyId: 'prop-017', floorLevel: 0, areaSqm: 350, available: true, rentPricePerSqm: 1140 },
],
@@ -1323,6 +1334,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BE-EXT-018',
description: 'Praktische Bürofläche im 2. Obergeschoss, Breitenrainstrasse Bern. Grosszügige, lichtdurchflutete Räume in ruhigem Quartier nahe dem Stadtzentrum. Bahn- und Busanbindung in 8 Minuten Fussweg. Ideal für Büros, Beratungsfirmen oder Praxen.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-018-1', propertyId: 'prop-018', floorLevel: 2, areaSqm: 780, available: true, rentPricePerSqm: 372 },
],
@@ -1361,6 +1373,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BS-MW-019',
description: 'Grosszügige Produktionshalle mit erhöhten Bodenlasten und Dreiphasenstrom im Industriequartier Kleinhüningen Basel. Direkte LKW-Zufahrt über die Voltastrasse. Ideal für Leichtindustrie, Montage oder Lagerhaltung.',
hardFacts: { fitOut: 'SHELL' },
units: [
{ id: 'unit-019-1', propertyId: 'prop-019', floorLevel: 0, unitLabel: 'Produktionshalle', areaSqm: 1900, available: true, rentPricePerSqm: 156 },
],
@@ -1404,6 +1417,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'ZG-MW-020',
description: 'Grosszügige Bürofläche im 4. Obergeschoss, Industriestrasse Zug. Ruhige Lage mit Panorama-Bergblick, direkter Autobahnanschluss A4. Ideal für Firmen, die von der Zuger Steuerpolitik profitieren möchten, ohne Premium-Innenstadtmieten zu zahlen.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-020-1', propertyId: 'prop-020', floorLevel: 4, areaSqm: 820, available: true, rentPricePerSqm: 528 },
],
@@ -1448,6 +1462,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'GE-MW-021',
description: 'Exklusive Verkaufsfläche im Erdgeschoss an der Rue du Rhône, Genf Zentrum. Eine der prestigeträchtigsten Einkaufsstrassen der Schweiz. Ideal für Luxusmarken, Juweliere oder hochwertige Dienstleister mit Anforderung an Prestige und Visibilität.',
hardFacts: { fitOut: 'PREMIUM' },
units: [
{ id: 'unit-021-1', propertyId: 'prop-021', floorLevel: 0, areaSqm: 250, available: true, rentPricePerSqm: 1344 },
],
@@ -1491,6 +1506,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'SG-EXT-022',
description: 'Helle Bürofläche an der Marktgasse im Zentrum St. Gallens. Das 2. Obergeschoss bietet eine zusammenhängende, gut aufteilbare Fläche in historischem Stadtquartier. St. Gallen HB in 6 Minuten zu Fuss. Ideal für Kanzleien, Dienstleister oder regionale Niederlassungen.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-022-1', propertyId: 'prop-022', floorLevel: 2, areaSqm: 700, available: true, rentPricePerSqm: 336 },
],
@@ -1694,6 +1710,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'ZH-EXT-031',
description: 'Repräsentative Bürofläche im 3. Obergeschoss im modernen Hardturm-Areal Zürich-West. Die zusammenhängende Fläche von 780 m² ist offen gestaltet und kann flexibel unterteilt werden. Grosse Fensterflächen, Klimaanlage und ein Untergeschoss-Parkhaus sind vorhanden. Das Gebäude befindet sich in zentraler Lage mit hervorragender Anbindung an den öffentlichen Verkehr (Tram 4/13, Bahnhof Hardbrücke, 4 Minuten zu Fuss). Übergabe ab Oktober 2025 möglich.',
hardFacts: { fitOut: 'FULL' },
units: [
{ id: 'unit-031-1', propertyId: 'prop-031', floorLevel: 3, areaSqm: 780, available: true, rentPricePerSqm: 420 },
],
@@ -1732,6 +1749,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'ZH-MW-032',
description: 'Stilvolles Büroloft im 5. Obergeschoss eines ehemaligen Industriegebäudes an der Pfingstweidstrasse, Kreis 5. Die offene Loftstruktur mit Sichtbetondecken und -wänden schafft ein inspirierendes Arbeitsumfeld. Raumhöhe ca. 3,5 m, Holzböden, individuelle Klimatisierung. Panoramablick über die Dächer Zürichs. Ideal für kreative Unternehmen und Tech-Firmen. Verfügbar ab November 2025.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-032-1', propertyId: 'prop-032', floorLevel: 5, areaSqm: 720, available: true, rentPricePerSqm: 480 },
],
@@ -1770,6 +1788,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BE-MW-033',
description: 'Attraktive Retailfläche an der Marktgasse, direkt in der Berner Fussgängerzone. EG-Fläche mit hoher Laufkundschaft durch Tourismus und Pendler. Tram und Bus direkt vor dem Haus. Ideal für Fashion, Lifestyle oder Gastronomie-Konzepte.',
hardFacts: { fitOut: 'FULL' },
units: [
{ id: 'unit-033-1', propertyId: 'prop-033', floorLevel: 0, areaSqm: 260, available: true, rentPricePerSqm: 1440 },
],
@@ -1808,6 +1827,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BE-EXT-034',
description: 'Ansprechende Ladenfläche im trendigen Quartier Lorraine, Bern. EG mit Schaufensterfront, gut positioniert für Kreativwirtschaft und gehobene Kundschaft. Busanbindung in 6 Minuten zum Bahnhof Bern.',
hardFacts: { fitOut: 'BASIC' },
units: [
{ id: 'unit-034-1', propertyId: 'prop-034', floorLevel: 0, areaSqm: 340, available: true, rentPricePerSqm: 1320 },
],
@@ -1872,6 +1892,7 @@ export const mockProperties: Property[] = [
mapImageUrl: 'https://images.unsplash.com/photo-1524661135-423995f22d0b?w=600&h=300&fit=crop',
propertyNumber: 'BS-EXT-036',
description: 'Freistehendes Lager-/Logistikgebäude direkt an der Klybeckstrasse, Basel Hafen. Ebenerdige Anlieferung, 38 Aussenparkplätze. Hervorragende Lage für Distribution in der Nordwestschweiz. Kran und Sprinkleranlage vorhanden.',
hardFacts: { fitOut: 'SHELL' },
units: [
{ id: 'unit-036-1', propertyId: 'prop-036', floorLevel: 0, unitLabel: 'Lagerhalle', areaSqm: 2600, available: true, rentPricePerSqm: 180 },
],
@@ -1909,6 +1930,7 @@ export const mockProperties: Property[] = [
parkingSpots: 0,
publicTransportMinutes: 3,
},
hardFacts: { fitOut: 'FULL' },
floorLevel: 0,
contractDurationMonths: 48,
ancillaryCosts: 4.0,
@@ -2486,7 +2508,7 @@ export const mockProperties: Property[] = [
parkingSpots: 5,
publicTransportMinutes: 6,
},
hardFacts: { floor: 2, parking: 5, fitOut: 'BASIC', ceilingHeightM: 2.8 },
hardFacts: { floor: 2, parking: 5, fitOut: 'BASIC', ceilingHeightM: 2.8, mieterausbaubeitragPerSqm: 250 },
floorLevel: 2,
contractDurationMonths: 84,
ancillaryCosts: 3.8,
@@ -3709,7 +3731,7 @@ export const mockProperties: Property[] = [
parkingSpots: 30,
publicTransportMinutes: 14,
},
hardFacts: { floor: 0, parking: 30, loadingDocksCount: 4, ceilingHeightM: 12.5, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 30, loadingDocksCount: 4, ceilingHeightM: 12.5, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 120,
ancillaryCosts: 2.5,
@@ -3761,7 +3783,7 @@ export const mockProperties: Property[] = [
parkingSpots: 35,
publicTransportMinutes: 12,
},
hardFacts: { floor: 0, parking: 35, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 35, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 120,
ancillaryCosts: 2.5,
@@ -3813,7 +3835,7 @@ export const mockProperties: Property[] = [
parkingSpots: 40,
publicTransportMinutes: 16,
},
hardFacts: { floor: 0, parking: 40, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 40, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 120,
ancillaryCosts: 2.2,
@@ -3866,7 +3888,7 @@ export const mockProperties: Property[] = [
parkingSpots: 50,
publicTransportMinutes: 18,
},
hardFacts: { floor: 0, parking: 50, loadingDocksCount: 4, ceilingHeightM: 12.0, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 50, loadingDocksCount: 4, ceilingHeightM: 12.0, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 60,
ancillaryCosts: 2.0,
@@ -3913,7 +3935,7 @@ export const mockProperties: Property[] = [
parkingSpots: 38,
publicTransportMinutes: 14,
},
hardFacts: { floor: 0, parking: 38, loadingDocksCount: 2, ceilingHeightM: 11.5, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 38, loadingDocksCount: 2, ceilingHeightM: 11.5, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 60,
ancillaryCosts: 2.5,
@@ -3958,7 +3980,7 @@ export const mockProperties: Property[] = [
parkingSpots: 35,
publicTransportMinutes: 14,
},
hardFacts: { floor: 0, parking: 35, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 35, loadingDocksCount: 3, ceilingHeightM: 12.0, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 120,
ancillaryCosts: 2.5,
@@ -4266,7 +4288,7 @@ export const mockProperties: Property[] = [
parkingSpots: 12,
publicTransportMinutes: 12,
},
hardFacts: { floor: 0, parking: 12, loadingDocksCount: 1, ceilingHeightM: 5.5, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 12, loadingDocksCount: 1, ceilingHeightM: 5.5, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 60,
ancillaryCosts: 2.8,
@@ -4318,7 +4340,7 @@ export const mockProperties: Property[] = [
parkingSpots: 18,
publicTransportMinutes: 15,
},
hardFacts: { floor: 0, parking: 18, loadingDocksCount: 2, ceilingHeightM: 6.0, isBarrierFree: true },
hardFacts: { fitOut: 'SHELL', floor: 0, parking: 18, loadingDocksCount: 2, ceilingHeightM: 6.0, isBarrierFree: true },
floorLevel: 0,
contractDurationMonths: 60,
ancillaryCosts: 2.5,