Anpassungsrunde 6. Die Kartendarstellung aus Runde 5 ist ersetzt: die Startseite zeigt oben einen räumlichen Meetingraum aus der Sicht des Betrachters, der selbst am Kopfende des Tisches sitzt. **3D statt Kulisse.** Zwei Versuche mit CSS-Flächen sind daran gescheitert, dass gezeichnete Wände neben fotografierten Porträts erkennbar gezeichnet bleiben. Diese Runde nutzt three.js — die einzige neue Abhängigkeit, und §19 lässt sie ausdrücklich zu, wenn eine schlanke 3D-Lösung die Anforderung trägt. Keine Engine darüber hinaus: kein React-Three-Fiber, keine Physik, keine Shader, keine Post-Processing-Kette, keine Orbit-Steuerung. Der Raum: Boden, Decke, rechts eine geschlossene Wand mit Eichenpaneel und einem schmalen Streifen im Markenblau, links und gegenüber bodentiefe Glasfassaden mit Pfosten. Draussen tragen die beiden Referenzfotos aus dem Auftrag die Basler Aussicht — vorne Rhein, Altstadt und Münster, links der Rheinverlauf mit der Wettsteinbrücke. Die Wasserlinie beider Kulissen liegt auf derselben Welthöhe, damit der Blick nach vorne und nach links zusammengehört und nicht wie zwei zusammengesetzte Bilder wirkt (§4). Am Tisch sitzen alle fünf bestehenden Agenten mit ihren bestehenden Porträts, Namen, Funktionen und Zielseiten — alles aus `AGENT_WORKSPACES`, damit nichts doppelt gepflegt wird (§24, Schritt 7). Neu ist Thomas, Personalverwalter, vis-à-vis am gegenüberliegenden Kopfende; sein Klick führt in die bestehende Ansicht «Meine Agenten». Gerendert wird nur bei Anlass — Grösse, Maus, Hover. Ein Dauerloop wäre für eine feste Szene verschwendete Rechenzeit (§21). Die Kamera folgt der Maus um wenige Zentimeter, mehr nicht (§20). Die Beschriftungen sind HTML über dem Bild, nicht Textur in der Szene: als Textur wären sie bei Tiefe unlesbar. Ein Entzerrungsdurchgang nach der Projektion hebt Plaketten so weit an, bis keine mehr überlappt — gerechnet und nicht handverlesen, damit es auf jeder Fenstergrösse hält. Bei Hover kommt eine Zeile mit der aktuellen Auslastung dazu; ruhend bleiben es Name und Funktion. **Navigation.** Die linke Seitenleiste ist gelöscht, nicht ausgeblendet: samt Breitenreservierung, Einklapplogik und mobilem Drawer. Der Inhalt beginnt überall bei x=0. An der Stelle des früheren Profilsymbols steht neben der Glocke ein Menüsymbol; das Klappmenü öffnet rechts an der Kopfzeile nach unten und führt Startseite, Meine Agenten samt aller Agenten als eingerückte, rechtsbündige Unterpunkte, und Profil mit Profil, Einstellungen, Produkttour und Abmelden. Alle Aktionen und Routen sind die bestehenden. Entfallen sind die Kartenkomponenten aus Runde 5 samt Präsenzschicht. Geprüft (§25): 422 Tests, Typecheck, Build, ESLint, Token-Schwelle (884/925). Im Browser 430–2560 px: keine alte Sidebar, kein leerer Streifen links, sechs Beschriftungen ohne Überlappung, alle sechs Agenten per Maus und per Tastatur erreichbar und auf der richtigen Subpage, Menü öffnet und schliesst per Klick und Escape, alle Menürouten korrekt, alle bestehenden Seiten laden, kein horizontaler Overflow, keine Konsolenfehler. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Property Match
Decision-Intelligence-Plattform für kommerziell genutzte Immobilien — kein Portal, sondern eine Oberfläche, die Treffer bewertet, Trade-offs erklärt und eine nächste Handlung empfiehlt.
Verbindliche Entwicklungsregeln stehen in CLAUDE.md, Architekturdiagramme in ARCHITECTURE.md, Zustandsregeln in STATE_MANAGEMENT.md.
Starten
npm install
npm run dev # Entwicklungsserver auf http://localhost:5173
Es gibt kein Backend und keine Datenbank. Sämtliche Daten stammen aus TypeScript-Mockdaten
unter src/mock-data/ und werden über Mockup-Provider bereitgestellt.
| Skript | Zweck |
|---|---|
npm run dev |
Entwicklungsserver mit HMR |
npm run build |
Typecheck (tsc -b) und Produktionsbuild |
npm run lint |
ESLint über das gesamte Projekt |
npm test |
Vitest einmalig ausführen |
npm run test:watch |
Vitest im Watch-Modus |
npm run check:tokens |
Zählt rohe Hex-Farbwerte gegen einen Schwellwert |
Architektur in vier Schichten
Provider → Service → Hook (React Query) → Component
- Provider (
src/provider/) sind der einzige Ort, der Datenhaltung berührt. - Services (
src/services/) tragen die Fachlogik und liefernListResponse<T>/ItemResponse<T>. - Hooks (
src/hooks/) kapseln React Query; Stale-Zeiten kommen aussrc/lib/constants.ts. - Komponenten (
src/components/,src/pages/) sind reine Darstellung.
Drei geschützte Arbeitsbereiche: /supply/* (Bewirtschaftung), /demand/* (Suche),
/ops/* (interner Betrieb).
Property On — «Teamübersicht»
Property On ist als Funktionsbereich in Property Match eingebettet, nicht als eigene Anwendung. Es gibt keine zweite App-Shell, keine zweite Sidebar und kein eigenes Branding. Erreichbar über den Hauptreiter Teamübersicht in der Bewirtschaftungs-Navigation, mit den Subreitern Personalverwaltung, Bearbeitungsverlauf und Kanäle & Systeme.
Bedienprinzip: human-led, agent-operated. Sieben digitale Mitarbeiter führen Arbeiten aus, der Mensch gibt frei, passt an oder weist zurück. Jede Entscheidung erzeugt einen Protokolleintrag, aktualisiert die Kennzahlen und meldet sich mit einer Rückmeldung.
Routen
/supply/team Teamübersicht (Startseite)
/supply/team/personalverwaltung Agentenliste + Dossier
/supply/team/personalverwaltung/:agentId Personalblatt
/supply/team/personalverwaltung/:agentId/:tab Dossier-Reiter, deep-linkbar
tab: aufgaben | kanaele | systeme
einstellungen | protokoll
/supply/team/bearbeitungsverlauf Vorgänge
/supply/team/bearbeitungsverlauf/:tab tab: pendente-anfragen | erledigte-auftraege
/supply/team/kanaele-systeme Verbindungen der Organisation
Architekturentscheidungen
Der Entitätstyp heisst TeamAgent, nicht Agent. Im Repo existiert bereits PowerOn als
Name des KI-Backend-Proxys, und Claude Code legt Arbeitskopien unter agent-* ab. Ein nackter
Typ Agent wäre in Suchen praktisch nicht auffindbar. Alle Satellitentypen tragen das Präfix
Agent* — AgentStatus, AgentChannelType, AgentProtocolEntry —, weil src/domain/index.ts
per export * bündelt und generische Namen dort kollidieren würden.
Eigener Protokolltyp statt ActivityEvent. Den Namen gibt es im Repo dreifach und
gegenseitig inkompatibel: in domain/activityEvent.ts, lokal in services/governanceService.ts
und noch einmal in components/supply/PropertyActivityLogPanel.tsx. Ein Anschluss an einen
dieser Typen hätte den Konflikt zementiert; AgentProtocolEntry steht bewusst daneben.
Verbindungen sind von DataSource getrennt. DataSource/ConnectorRun modelliert
Crawler-Quellen mit AGB-Status und Crawl-Läufen. «Kanäle & Systeme» beschreibt angebundene
Kommunikationskanäle und Fachsysteme — fachlich etwas anderes. Die Ops-Komponenten dienten als
visuelles Vorbild, das Datenmodell ist eigenständig.
Eine Demo-Uhr statt der Systemzeit (src/lib/teamClock.ts). Die Mockdaten sind fachlich
auf den 20.05.2026 verankert. Gegen die echte Systemzeit gerechnet wären die Zeitraumfilter
«heute / diese Woche / dieser Monat» an jedem anderen Kalendertag leer, und die Auswertung
sähe kaputt aus, obwohl sie korrekt arbeitet. Die Demo-Uhr startet am Anker und läuft ab
Anwendungsstart in Echtzeit weiter — jede Freigabe während einer Vorführung landet damit
verlässlich im Bucket «heute». Sie gilt ausschliesslich für Property On.
Persistenz liegt in der Providerschicht. Geänderte Einstellungen, Aufgabenschalter,
erledigte Vorgänge, Verbindungsstatus und pausierte Mitarbeiter überleben einen Reload über
den Local Storage. Die Bestände tragen eine Schemaversion (TEAM_SCHEMA_VERSION): passt sie
nicht, greift wieder der Seed aus src/mock-data/ — sonst überlagerte ein alter Eintrag
stillschweigend geänderte Mockdaten. «Demo zurücksetzen» löscht genau diese Schlüssel.
Subreiter sind echte Routen, keine lokalen Tabs. Die Anwendung kannte bis dahin keine
Feature-Route mit eigenem <Outlet/>, und Tabs werden sonst über lokalen useState gebaut.
Hier war das nicht tragfähig: die drei Subreiter müssen in der Sidebar sichtbar sein und
deep-linkbar bleiben. Das NavItem-Modell in appShellConfig.ts wurde deshalb um children
erweitert; die Routen sind flache Geschwister, kein Outlet-Baum.
Kein neuer Stack. Der ursprüngliche Auftrag nannte shadcn/ui, React Hook Form, date-fns und
Playwright. Nichts davon ist installiert, und die Vorgabe, die bestehenden Property-Match-Muster
zu übernehmen, wiegt schwerer. Umgesetzt mit MUI v9, TanStack Query, Zustand und Zod;
Datumsformatierung über Intl in src/lib/utils.ts und src/lib/teamClock.ts. Besonders
relevant: Tailwind-Preflight ist bewusst nicht importiert — shadcn erwartet es und würde den
CssBaseline-Reset von MUI überschreiben.
Simulation
Alles ist Frontend-Simulation. Es gibt keine echten Systemverbindungen, keine echten Zugangsdaten und keine echten Modellaufrufe. Simulierte Ladezeiten liegen zwischen 300 und 800 ms. Der Test einer Verbindung ist deterministisch und nicht zufällig: verbundene Kanäle gelingen, nicht verbundene und geplante scheitern reproduzierbar — ein Zufallsfehler würde eine Kundendemo unvorhersehbar machen.
Bekannte Altlasten
npm run check:tokensliegt bei 2249 rohen Hex-Werten über dem Schwellwert von 1958. Der Wert stammt vollständig aus dem Bestand; Property On hat null hinzugefügt. Der Schwellwert darf laut Skript nicht angehoben werden.npm run lintmeldet im Bestand weiterhin Fehler und Warnungen. Der Property-On-Code ist frei davon:npx eslint src/components/team src/pages/supply/Teamuebersicht.tsx …ist grün.- In
tsconfigiststrictentgegen CLAUDE.md §14 nicht gesetzt;strictNullChecksfehlt damit projektweit.