feat(agenten): Runde 4 — «Meine Agenten» mit fünf digitalen Mitarbeitenden

Setzt das Umsetzungsbriefing Runde 4 im bestehenden Frontend um.

Informationsarchitektur
- «Teamübersicht» heisst «Meine Agenten»; ihr bisheriger Inhalt (Kreisgrafik,
  Auswertung, Verbindungszusammenfassung) ist entfallen.
- Personalverwaltung, Bearbeitungsverlauf und Kanäle & Systeme sind jetzt
  Reiter derselben Seite (?section=), gestaltet wie die Auswahl im
  Bearbeitungsverlauf. Es wird nur der gewählte Bereich gerendert.
- Die alten Unterseitenpfade leiten um, damit Lesezeichen nicht brechen.

Agentenbestand
- Reto und Lea vollständig entfernt — aus Navigation, Dossiers, Protokoll,
  Verbindungen, Vorgängen und Porträtbestand.
- Retos Aufgaben liegen bei Bruno: Nachbereitung, WhatsApp-Anruf,
  Protokoll und Kundennotiz, Ablage im CRM.
- Livia ist «Exposé Master»: Lageberichte, Inserate, Angebotsbroschüren.
- Sidebar führt Ferdi, Bruno, Livia, Nora, Sina mit Porträt und Funktion.

Agentenseiten
- Ein gemeinsamer AgentWorkspaceHero auf allen fünf Seiten.
- Ferdi: Auswertungskarten, Priorität und Typfarben entfallen; Fälligkeit nur
  bei fünf Tagen oder weniger rot; Objektlinks nach «Meine Objekte»; neu die
  Terminplanung im verbundenen Kalender mit typgerechtem PDF-Ausschnitt.
- Sina: reduzierte, filter- und sortierbare Objektübersicht; Detailansicht
  direkt editierbar, leere Pflichtfelder rot umrandet.
- Nora: Signale ohne Prozentsätze und Konfidenzstufen, nur belegbare Angaben;
  Mehrfachauswahl leitet Objekte an Livia weiter.
- Livia: aktive und archivierte Leads, Arbeitsbereich gleitet an den oberen
  Rand; dreistufiger Exposé-Prozess Hochladen → Exposé → Export.
- Bruno: neue Seite mit Auftragsliste und Vor-/Nachbereitungs-Drawer;
  Glocke warnt bei Besichtigung unter 24 Stunden ohne Bericht.

Datenschicht
- Neu: Kalender, Exposé-Leads, Exposé-Entwürfe, Besichtigungsaufträge —
  je Domain, Provider, Service und Hook.
- IAIService um generateExposeText erweitert; der Entwurf nutzt ausschliesslich
  erfasste Objektdaten und meldet Lücken, statt sie zu füllen.
- Alle Objektverweise zeigen auf reale Einträge aus «Meine Objekte»; neue
  Detailroute /supply/properties/:propertyId.

Offen: Chat, Kalender, CRM und DMS sind Frontend-Simulation ohne Anbindung.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-08-05 14:43:16 +02:00
parent cc5582b7fd
commit d200d4e930
352 changed files with 8069 additions and 8512 deletions
+7 -203
View File
@@ -1,5 +1,5 @@
/**
* Property On — Protokoll der sieben digitalen Mitarbeiter.
* Property On — Protokoll der fünf digitalen Mitarbeiter.
*
* Jeder Eintrag hält fest, was ein Agent getan hat, wer es ausgelöst hat und mit
* welchem Ergebnis. Die Liste ist absteigend nach Zeitstempel sortiert; die
@@ -29,7 +29,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
// ── Heute, 20.05.2026 ───────────────────────────────────────────────────────
{
id: 'proto-001',
agentId: AGENT_IDS.RETO,
agentId: AGENT_IDS.BRUNO,
timestamp: '2026-05-20T16:42:00.000Z',
eventType: AgentProtocolEventType.TASK_RUN,
title: 'Sprachmemo zur Besichtigung Technoparkstrasse 9 verarbeitet',
@@ -111,7 +111,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
{
id: 'proto-002',
agentId: AGENT_IDS.RETO,
agentId: AGENT_IDS.BRUNO,
timestamp: '2026-05-20T16:05:00.000Z',
eventType: AgentProtocolEventType.APPROVAL,
title: 'Recap-Paket zur Besichtigung Industriestrasse 14 freigegeben',
@@ -124,76 +124,6 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
triggeredByName: OPERATOR,
approvalDecision: AgentApprovalDecision.APPROVED,
},
{
id: 'proto-003',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-20T15:20:00.000Z',
eventType: AgentProtocolEventType.MESSAGE_PROCESSED,
title: 'Portal-Anfrage zur Hardturmstrasse 118 qualifiziert',
description:
'Lead-Mail einer Plattform erfasst, in ein einheitliches Bedarfsprofil überführt und gegen die Must-Kriterien der Fläche geprüft. Alle fünf Kriterien sind erfüllt; das Kurzprofil liegt zur Entscheidung bereit.',
status: AgentProtocolStatus.SUCCESS,
objectId: 'OBJ-2512',
channel: AgentChannelType.PORTAL_LEAD_MAIL,
triggeredBy: AgentTriggerSource.SYSTEM,
input: [
{ label: 'Herkunftskanal', value: 'Portal-Lead-Mail, Eingang 20.05.2026, 15:12' },
{ label: 'Interessent', value: 'Limmat Robotics AG, Zürich — R. Amrein, Geschäftsleitung' },
{
label: 'Anfragetext',
value:
'«Wir suchen per Herbst 2026 rund 500 m² Bürofläche in Zürich West, gerne mit Werkstattanteil im Erdgeschoss.»',
},
{ label: 'Objektbezug', value: 'OBJ-2512, Hardturmstrasse 118, Zürich Kreis 5' },
],
processingSteps: [
{
id: 'proto-003-ps-1',
label: 'Lead-Mail erfasst und der ausgeschriebenen Fläche zugeordnet',
},
{
id: 'proto-003-ps-2',
label: 'Freitext in ein Bedarfsprofil überführt',
detail: 'Fläche, Nutzungsart, Wunschtermin, Budgetrahmen und Vertragsdauer übernommen',
},
{
id: 'proto-003-ps-3',
label: 'Abgleich über die letzten 90 Tage auf Mehrfachanfragen',
detail: 'Keine Übereinstimmung über Portal, Formular oder Telefon gefunden',
},
{ id: 'proto-003-ps-4', label: 'Bedarfsprofil gegen die Must-Kriterien der Fläche geprüft' },
{ id: 'proto-003-ps-5', label: 'Kurzprofil zur Entscheidung vorgelegt' },
],
output: [
{ label: 'Bedarfsprofil', value: '480560 m², Büro mit Werkstattanteil, Bezug ab 01.10.2026' },
{
label: 'Kriterienprüfung',
value: [
'Flächenbedarf im ausgeschriebenen Rahmen — erfüllt',
'Nutzungsart für das Objekt zulässig — erfüllt',
'Wunschtermin passt zur Verfügbarkeit — erfüllt',
'Budgetrahmen erreicht die Mietpreisvorstellung — erfüllt',
'Bonitätsnachweis kann beigebracht werden — erfüllt',
],
},
{ label: 'Nächster Schritt', value: 'Freigabe für Terminvorschläge einholen' },
],
sourceReferences: [
{
id: 'proto-003-src-1',
label: 'Must-Kriterien der Fläche',
documentName: 'Vermarktungsauftrag Hardturmstrasse 118.pdf',
locator: 'Seite 2, Abschnitt «Zielmieterschaft»',
quote: '«Mindestvertragsdauer fünf Jahre, Nutzung Büro und stiller Werkstattbetrieb zulässig»',
},
{
id: 'proto-003-src-2',
label: 'Flächenstammdaten OBJ-2512',
documentName: 'Bewirtschaftungssystem — Objektblatt OBJ-2512',
locator: 'Verfügbarkeit ab 01.09.2026',
},
],
},
{
id: 'proto-004',
agentId: AGENT_IDS.BRUNO,
@@ -517,21 +447,6 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
],
},
{
id: 'proto-010',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-20T08:20:00.000Z',
eventType: AgentProtocolEventType.REJECTION,
title: 'Absageentwurf an die Säntis Retail AG zurückgewiesen',
description:
'Der vorbereitete Absagetext wurde nicht freigegeben: Der Flächenbedarf liegt nur knapp unter dem ausgeschriebenen Rahmen, der Fall gilt damit als Grenzfall. Die Anfrage ist zurück in die Entscheidung gelegt worden.',
status: AgentProtocolStatus.SUCCESS,
objectId: 'OBJ-2568',
channel: AgentChannelType.EMAIL,
triggeredBy: AgentTriggerSource.USER,
triggeredByName: OPERATOR,
approvalDecision: AgentApprovalDecision.REJECTED,
},
{
id: 'proto-011',
agentId: AGENT_IDS.FERDI,
@@ -601,21 +516,6 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
// ── Laufende Woche, 18.19.05.2026 ──────────────────────────────────────────
{
id: 'proto-012',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-19T17:05:00.000Z',
eventType: AgentProtocolEventType.APPROVAL,
title: 'Terminvorschläge für die Limmat Robotics AG freigegeben',
description:
'Nach der Freigabe sind drei Zeitfenster im Besichtigungskalender vorläufig reserviert und dem Interessenten zugestellt worden. Termindauer 45 Minuten, Pufferzeit 15 Minuten vor und nach dem Termin.',
status: AgentProtocolStatus.SUCCESS,
objectId: 'OBJ-2512',
channel: AgentChannelType.CALENDAR,
triggeredBy: AgentTriggerSource.USER,
triggeredByName: OPERATOR,
approvalDecision: AgentApprovalDecision.APPROVED,
},
{
id: 'proto-013',
agentId: AGENT_IDS.NORA,
@@ -632,7 +532,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
{
id: 'proto-014',
agentId: AGENT_IDS.RETO,
agentId: AGENT_IDS.BRUNO,
timestamp: '2026-05-19T14:12:00.000Z',
eventType: AgentProtocolEventType.TASK_RUN,
title: 'Kein Systemzugang zum Kontaktjournal — Mail-Fallback gegriffen',
@@ -676,7 +576,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
{
id: 'proto-014-src-1',
label: 'Fallback-Einstellung',
documentName: 'Einstellungen Reto — Fallback-Ziel',
documentName: 'Einstellungen Bruno — Fallback-Ziel',
locator: 'Wert «Strukturierter Mail-Fallback an die zuständige Person»',
},
{
@@ -813,33 +713,8 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
channel: AgentChannelType.WORKSPACE_CHAT,
triggeredBy: AgentTriggerSource.SYSTEM,
},
{
id: 'proto-021',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-18T06:40:00.000Z',
eventType: AgentProtocolEventType.MESSAGE_PROCESSED,
title: 'Telefonnotiz aus dem Empfang Winterthur nur teilweise auswertbar',
description:
'Aus der Notiz liessen sich Name und Firma übernehmen, Flächenbedarf und Wunschtermin fehlen. Ein Rückfrageentwurf mit den fehlenden Mindestangaben liegt zur Freigabe bereit; die Anfrage bleibt bis dahin offen.',
status: AgentProtocolStatus.WARNING,
objectId: 'OBJ-2568',
channel: AgentChannelType.PHONE_NOTE,
triggeredBy: AgentTriggerSource.SYSTEM,
},
// ── Laufender Monat, 01.15.05.2026 ─────────────────────────────────────────
{
id: 'proto-022',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-15T15:45:00.000Z',
eventType: AgentProtocolEventType.SETTINGS_SAVED,
title: 'Must-Kriterien und Termindauer gespeichert',
description:
'Das Kriterium «Vertragsdauer mindestens fünf Jahre» wurde ergänzt und die Termindauer von 60 auf 45 Minuten gesetzt. Die Änderung gilt ab dem nächsten Anfrageeingang.',
status: AgentProtocolStatus.SUCCESS,
triggeredBy: AgentTriggerSource.USER,
triggeredByName: OPERATOR,
},
{
id: 'proto-023',
agentId: AGENT_IDS.SINA,
@@ -947,7 +822,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
{
id: 'proto-027',
agentId: AGENT_IDS.RETO,
agentId: AGENT_IDS.BRUNO,
timestamp: '2026-05-08T16:30:00.000Z',
eventType: AgentProtocolEventType.REMINDER_SENT,
title: 'Erinnerung an fehlendes Diktat nach der Besichtigung Industriestrasse 14',
@@ -971,19 +846,6 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
channel: AgentChannelType.WORKSPACE_CHAT,
triggeredBy: AgentTriggerSource.SYSTEM,
},
{
id: 'proto-029',
agentId: AGENT_IDS.LEA,
timestamp: '2026-05-06T13:40:00.000Z',
eventType: AgentProtocolEventType.REMINDER_SENT,
title: 'Terminreminder 24 Stunden vor der Besichtigung versandt',
description:
'Interessent und Ansprechperson wurden an die Besichtigung vom 07.05.2026, 09:30 Uhr erinnert — mit Treffpunkt, Dauer und Ansprechperson vor Ort. Beide haben den Termin bestätigt.',
status: AgentProtocolStatus.SUCCESS,
objectId: 'OBJ-2512',
channel: AgentChannelType.EMAIL,
triggeredBy: AgentTriggerSource.SYSTEM,
},
{
id: 'proto-030',
agentId: AGENT_IDS.NORA,
@@ -1067,7 +929,7 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
},
{
id: 'proto-033',
agentId: AGENT_IDS.RETO,
agentId: AGENT_IDS.BRUNO,
timestamp: '2026-04-08T09:45:00.000Z',
eventType: AgentProtocolEventType.EDIT,
title: 'Besichtigungsprotokoll vor der Freigabe angepasst',
@@ -1119,64 +981,6 @@ export const mockAgentProtocol: AgentProtocolEntry[] = [
triggeredBy: AgentTriggerSource.USER,
triggeredByName: OPERATOR,
},
{
id: 'proto-037',
agentId: AGENT_IDS.LEA,
timestamp: '2026-02-19T16:35:00.000Z',
eventType: AgentProtocolEventType.MESSAGE_PROCESSED,
title: 'Anfragen-Postfach nicht erreichbar — 14 Anfragen unbearbeitet',
description:
'Das Anfragen-Postfach der Vermarktung liess sich über zwei Stunden nicht öffnen. 14 eingegangene Anfragen wurden weder erfasst noch beantwortet; die durchschnittliche Erstreaktionszeit stieg an diesem Tag auf 3 Stunden 40 Minuten.',
status: AgentProtocolStatus.ERROR,
channel: AgentChannelType.EMAIL,
triggeredBy: AgentTriggerSource.SYSTEM,
input: [
{ label: 'Betroffenes Postfach', value: 'Anfragen-Postfach Vermarktung' },
{ label: 'Ausfallzeitraum', value: '19.02.2026, 14:20 bis 16:30' },
{
label: 'Betroffene Kanäle',
value: ['Direktmails von Interessenten', 'Website-Formular «Fläche anfragen»'],
},
],
processingSteps: [
{ id: 'proto-037-ps-1', label: 'Abruf des Postfachs planmässig gestartet' },
{
id: 'proto-037-ps-2',
label: 'Postfach nicht erreichbar',
detail: 'Acht Versuche im Abstand von fünfzehn Minuten, alle ohne Verbindung',
},
{
id: 'proto-037-ps-3',
label: 'Automatische Absagen für den Zeitraum ausgesetzt',
detail: 'Ohne vollständiges Bedarfsprofil wird nie abgesagt',
},
{ id: 'proto-037-ps-4', label: 'Störung an die Vermarktung gemeldet' },
{ id: 'proto-037-ps-5', label: 'Nachlauf nach Wiederherstellung eingeplant' },
],
output: [
{ label: 'Nicht erfasste Anfragen', value: '14, davon 9 über das Website-Formular' },
{ label: 'Erstreaktionszeit an diesem Tag', value: '3 Std. 40 Min. statt 11 Minuten' },
{
label: 'Behebung',
value:
'Nach Wiederherstellung um 16:30 wurden alle 14 Anfragen nacherfasst, dedupliziert und bis 18:10 qualifiziert.',
},
],
sourceReferences: [
{
id: 'proto-037-src-1',
label: 'Protokoll der Abrufversuche',
documentName: 'Systemprotokoll Lea — Postfachabrufe 19.02.2026',
locator: 'Einträge 14:20 bis 16:20',
},
{
id: 'proto-037-src-2',
label: 'Störungsmeldung an die Vermarktung',
documentName: 'Team-Kanal Vermarktung Zürich',
locator: 'Meldung vom 19.02.2026, 14:52',
},
],
},
{
id: 'proto-038',
agentId: AGENT_IDS.BRUNO,