# 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](./CLAUDE.md), Architekturdiagramme in
[ARCHITECTURE.md](./ARCHITECTURE.md), Zustandsregeln in [STATE_MANAGEMENT.md](./STATE_MANAGEMENT.md).

## Starten

```bash
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 liefern `ListResponse<T>` / `ItemResponse<T>`.
- **Hooks** (`src/hooks/`) kapseln React Query; Stale-Zeiten kommen aus `src/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:tokens` liegt 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 lint` meldet 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 `tsconfig` ist `strict` entgegen CLAUDE.md §14 nicht gesetzt; `strictNullChecks` fehlt
  damit projektweit.
