feat(team): Kreisdarstellung der Belegschaft und Organigramm-Ansicht

Setzt die Referenzgrafik «Agenten_Bewirtschaftung_v2» um: die 36 digitalen
Mitarbeitenden in konzentrischen Ringen, Kernteam innen und gold gerahmt.

DATENBASIS
Alle 36 Mitarbeitenden samt Porträts sind aus dem Konzeptdokument extrahiert.
Die Stufen stecken bereits in den Quelldaten und decken sich exakt mit den
Bereichen: lvl 1 = 7 Kernteam, lvl 2 = 18 Zentrale Dienste, lvl 3 = 7 GB
Kommerziell, lvl 4 = 4 GB Wohnen. Auch die Reiterbeschriftungen sind wörtlich
übernommen — keine neuen Stufennamen erfunden.

Neu getrennt: `AgentDirectoryEntry` trägt die Stammdaten aller 36 für die
Kreisdarstellung, `TeamAgent` bleibt das vollständige Dossier der sieben
Kernteammitglieder. Für die übrigen 29 werden bewusst keine Aufgaben, Kanäle
oder Tätigkeiten erfunden; ein Klick zeigt nur eine Vorschau aus dem Verzeichnis.

ABWEICHUNG VOM AUFTRAG
Der Auftrag nennt als Kernteam Ferdi, Sami, Leo, Bruno, Reto, Milo, Nora.
Referenzgrafik und Konzeptdaten sagen übereinstimmend Ferdi, Sina, Lea, Bruno,
Reto, Livia, Nora — dort tragen genau diese sieben `kern: true` und `lvl: 1`.
Da der Auftrag die Grafik selbst als verbindlich erklärt und Namen laut §10 kein
Primärschlüssel sind, folge ich Grafik und Daten. Sami, Leo und Milo kommen in
keiner Quelle vor.

OBERFLÄCHE
- Teamübersicht: Beschreibungstext und «Demo zurücksetzen» entfernt, Kreis mit
  kumulativen Stufenreitern direkt unter dem Titel
- Personalverwaltung: Umschaltung Dossieransicht / Organigramm über ?view=,
  Organigramm als oben abgeschnittener Halbkreis mit drehbarem Agentenrad
  (Ziehen, Touch, Pfeiltasten, Klick), aktiv ist wer unten mittig einrastet
- Dossier: Untermenü direkt unter den Stammdaten, «Agentenbeschrieb» als erster
  Reiter, Zuständigkeiten auf drei gekürzt
- Kanäle & Systeme: vier Karten pro Zeile, Kategorie-Sinnbild links vor dem
  Titel, Porträtgruppe statt Namensliste, ein Regler statt Verbinden/Trennen
- Bearbeitungsverlauf: neutrale Karten, Farbe nur noch bei Ausnahmepriorität und
  abweichendem Status, mehr Weissraum

Markenlogos gibt es im Repo nicht und wurden nicht nachgezeichnet — je Kategorie
steht ein neutrales Sinnbild. Fehlendes Asset, bewusst so gelöst.

Positionsdaten stehen ausschliesslich in `agentRingConfig.ts`; Vollkreis und
Halbkreis teilen sich dieselbe Geometrie.

AUFGERÄUMT
`AgentCard` ist durch die Kreisdarstellung ersetzt und entfernt, seine Zusagen
sind in `TeamOverviewRing.test.tsx` übergegangen — inklusive der wichtigsten:
ausserhalb des Kernteams führt kein Klick in ein Dossier.

Zwei echte Fehler unterwegs behoben: jsdom kennt keinen `ResizeObserver` (jetzt
mit Rückfallebene statt Absturz), und das Rad las eine Ref im Render.

413 Tests grün, Build grün, ESLint über den Property-On-Code sauber,
check:tokens unverändert bei 2249.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Sutter
2026-08-03 21:42:04 +02:00
parent 576733d7da
commit 8377ce03b5
61 changed files with 2499 additions and 642 deletions
+385
View File
@@ -0,0 +1,385 @@
/**
* Property On — Verzeichnis aller digitalen Mitarbeitenden.
*
* Quelle ist das Konzeptdokument «Agenten_Bewirtschaftung_v2.html» (Stand
* 24.07.2026): Namen, Funktionen, Personalstufen, Bereiche und Rollout-Status
* sind daraus unverändert übernommen, ebenso die Porträts.
*
* Abgrenzung zu `mockTeamAgents`: dieses Verzeichnis trägt nur die Stammdaten,
* die für die Kreisdarstellung nötig sind. Ein vollständiges Personaldossier —
* Aufgaben, Kanäle, Systemzugänge, Einstellungen, Protokoll — besitzen
* ausschliesslich die sieben Kernteammitglieder in `src/mock-data/agents/`.
* Für die übrigen 29 werden bewusst keine Inhalte erfunden.
*
* ACHTUNG: generiert aus dem Konzept. Nicht von Hand pflegen — bei einer neuen
* Konzeptfassung neu erzeugen, sonst driften Verzeichnis und Quelle auseinander.
*/
import type { AgentDirectoryEntry } from '../domain/agentDirectory'
import { AgentLevel, AgentDepartment, AgentRollout } from '../domain/agentDirectory'
export const agentDirectory: AgentDirectoryEntry[] = [
{
id: 'bruno',
name: 'Bruno',
role: 'Besichtigungs-Briefing',
email: 'bruno@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.IN_PROGRESS,
isCore: true,
},
{
id: 'ferdi',
name: 'Ferdi',
role: 'Fristen-Wächter',
email: 'ferdi@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PROTOTYPE,
isCore: true,
},
{
id: 'lea',
name: 'Lea',
role: 'Anfragen-Manager',
email: 'lea@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PROTOTYPE,
isCore: true,
},
{
id: 'livia',
name: 'Livia',
role: 'Lage-Analyst',
email: 'livia@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.IN_PROGRESS,
isCore: true,
},
{
id: 'nora',
name: 'Nora',
role: 'Markt-Scout',
email: 'nora@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PROTOTYPE,
isCore: true,
},
{
id: 'reto',
name: 'Reto',
role: 'Recap-Agent',
email: 'reto@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.IN_PROGRESS,
isCore: true,
},
{
id: 'sina',
name: 'Sina',
role: 'Vertragsauskunft',
email: 'sina@property-on.ch',
level: AgentLevel.CORE,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.IN_PROGRESS,
isCore: true,
},
{
id: 'ada',
name: 'Ada',
role: 'Datenqualitäts-Wächterin',
email: 'ada@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PROTOTYPE,
isCore: false,
},
{
id: 'carla',
name: 'Carla',
role: 'Bestands-Radar',
email: 'carla@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'diego',
name: 'Diego',
role: 'Decision-Brief-Ersteller',
email: 'diego@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PROTOTYPE,
isCore: false,
},
{
id: 'dora',
name: 'Dora',
role: 'Dossier-Erstellerin',
email: 'dora@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'emil',
name: 'Emil',
role: 'Unterlagen-Versand',
email: 'emil@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'filip',
name: 'Filip',
role: 'Ablage-Agent',
email: 'filip@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'kira',
name: 'Kira',
role: 'Konkurrenz-Beobachterin',
email: 'kira@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'lars',
name: 'Lars',
role: 'Archiv-Digitalisierer',
email: 'lars@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'mia',
name: 'Mia',
role: 'Mietpreis-Benchmarkerin',
email: 'mia@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'paul',
name: 'Paul',
role: 'Pipeline-Führer',
email: 'paul@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'pia',
name: 'Pia',
role: 'Mietantritt-Koordinatorin',
email: 'pia@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'rea',
name: 'Rea',
role: 'Referenz-Einholerin',
email: 'rea@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'rico',
name: 'Rico',
role: 'Eigentümer-Reporter',
email: 'rico@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'uli',
name: 'Uli',
role: 'Übergabe-Assistent',
email: 'uli@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'vela',
name: 'Vela',
role: 'Cockpit-Agentin',
email: 'vela@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'vera',
name: 'Vera',
role: 'Inserat-Texterin',
email: 'vera@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'vinz',
name: 'Vinz',
role: 'Vertragsentwurf-Assistent',
email: 'vinz@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'vito',
name: 'Vito',
role: 'Objekt-Erfasser',
email: 'vito@property-on.ch',
level: AgentLevel.CENTRAL_SERVICES,
department: AgentDepartment.CENTRAL_SERVICES,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'beat',
name: 'Beat',
role: 'Zahlungs-Frühwarner',
email: 'beat@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'fabio',
name: 'Fabio',
role: 'Fit-out-Rechner',
email: 'fabio@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'nadia',
name: 'Nadia',
role: 'Umsatzmiete-Abrechnerin',
email: 'nadia@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'oskar',
name: 'Oskar',
role: 'Offerten-Schreiber',
email: 'oskar@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'otto',
name: 'Otto',
role: 'Options-Vorbereiter',
email: 'otto@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PLANNED,
isCore: false,
},
{
id: 'sven',
name: 'Sven',
role: 'Mieter-Check',
email: 'sven@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.PROTOTYPE,
isCore: false,
},
{
id: 'tino',
name: 'Tino',
role: 'Mietzins-Rechner',
email: 'tino@property-on.ch',
level: AgentLevel.COMMERCIAL,
department: AgentDepartment.COMMERCIAL,
rollout: AgentRollout.IN_PROGRESS,
isCore: false,
},
{
id: 'gian',
name: 'Gian',
role: 'Privat-Check',
email: 'gian@property-on.ch',
level: AgentLevel.RESIDENTIAL,
department: AgentDepartment.RESIDENTIAL,
rollout: AgentRollout.IN_PROGRESS,
isCore: false,
},
{
id: 'ida',
name: 'Ida',
role: 'Nebenkosten-Assistentin',
email: 'ida@property-on.ch',
level: AgentLevel.RESIDENTIAL,
department: AgentDepartment.RESIDENTIAL,
rollout: AgentRollout.IN_PROGRESS,
isCore: false,
},
{
id: 'jana',
name: 'Jana',
role: 'Wechsel-Koordinatorin Wohnen',
email: 'jana@property-on.ch',
level: AgentLevel.RESIDENTIAL,
department: AgentDepartment.RESIDENTIAL,
rollout: AgentRollout.IN_PROGRESS,
isCore: false,
},
{
id: 'zeno',
name: 'Zeno',
role: 'Referenzzins-Spezialist',
email: 'zeno@property-on.ch',
level: AgentLevel.RESIDENTIAL,
department: AgentDepartment.RESIDENTIAL,
rollout: AgentRollout.IN_PROGRESS,
isCore: false,
},
]
/** Nur die sieben Kernteammitglieder — sie besitzen ein vollständiges Dossier. */
export const coreAgentIds: string[] = agentDirectory.filter(a => a.isCore).map(a => a.id)