# P06 · CRM (R-P6 → D-CRM) > Interim-UI-Referenz (AD-28). Jeder Screen unten ist als lauffähiger `Page`-Vorschau-Screen aus `~/ui` > gebaut (VM als Prop) und liegt im gebundelten Checkout unter `03 Quellen und Referenzen/hivegrid-cloud/`. > **Layout = Davids freie Hand** — die Listen unten nennen nur benötigte Elemente/Daten/Aktionen, keine Anordnung. ### KontaktListPage · D-CRM "Kontakt-Liste"/"Organisationen-Liste", archetype A2 - **Interim-Screen:** `apps/web/app/components/screens/crm/KontaktListPage.tsx` - **Route(n):** `/app/:tenant/contacts` (`routes/app.$tenant/contacts._index.tsx`) · `/app/:tenant/contacts/companies` (`routes/app.$tenant/contacts.companies._index.tsx`) — ein Screen, prop `variant: "contacts" | "companies"` - **Daten (VM):** `KontaktListVM` — `packages/view-models/src/crm/kontakt-list.vm.ts` - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Button, Checkbox, EmptyState, Select, Table, TextInput · Icons: FeatherDownload, FeatherPlus - **Interaktionen (Actions):** `onApplyFilter(query: KontaktListQuery)`, `onGoToPage(page: number)`, `onBulk(intent: "bulkArchive"|"bulkReassign"|"bulkTag", ids: string[], extra?: {zustaendigerUserId?, tagId?})`, `onNew()`, `onExport()` - **States:** Empty (EmptyState, leere Liste) · Permission-Denied/Modul-gesperrt (EmptyState `crm.locked.*`; Route 404 wenn nicht sichtbar) · Error (BadgeFeedback `subtle-negative`). CTA/Bulk/Admin-Nav gated über `canWrite`/`canAdmin` - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: ### KontaktDetailPage · D-CRM "Kontakt-Detail"/"Organisation-Detail", archetype A3 (master template) - **Interim-Screen:** `apps/web/app/components/screens/crm/KontaktDetailPage.tsx` - **Route(n):** `/app/:tenant/contacts/:id` (`routes/app.$tenant/contacts.$id.tsx`) · `/app/:tenant/contacts/companies/:id` (`routes/app.$tenant/contacts.companies.$id.tsx`) - **Daten (VM):** `KontaktDetailData` (aus `KontaktDetailVM`) + `ActivityStreamVM` — `packages/view-models/src/crm/kontakt-detail.vm.ts` (+ `packages/view-models/src/crm/activity-stream.vm.ts`) - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Breadcrumbs, Button, Card, Checkbox, EmptyState, Select, TextArea, TextInput · Icons: keine - **Interaktionen (Actions):** ein Callback `onSubmit(intent: string, fields?: Record)`; Intents: `updateBasics`, `addEmail`/`removeEmail`/`setPrimaryEmail`, `addTelefon`/`removeTelefon`/`setPrimaryTelefon`, `addRelation`/`removeRelation`, `addTag`/`removeTag`, `setCustomField`, `reassign`, `addNote`, `archive`/`reactivate`, `delete` - **States:** Empty (Activity-Stream: EmptyState `crm.detail.activityEmpty`) · Permission-Denied(404) auf Route-Ebene · Error (BadgeFeedback). Alle Edit-Blöcke gated über `data.canWrite`/`data.canDelete` - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: ### KontaktNewPage · D-CRM "Kontakt anlegen", archetype A4 - **Interim-Screen:** `apps/web/app/components/screens/crm/KontaktNewPage.tsx` - **Route(n):** `/app/:tenant/contacts/new` (`routes/app.$tenant/contacts.new.tsx`) - **Daten (VM):** kein `@hivegrid/view-models`-Import — Formular hält lokalen Draft `KontaktNewFields`; Live-Duplikate über prop `duplicates: KontaktNewDuplicates` (route-geliefert, `{hard, soft}` von `KontaktNewDuplicateCard`) - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Breadcrumbs, Button, Card, Select, TextInput · Icons: keine - **Interaktionen (Actions):** `onCheckDuplicates(fields: KontaktNewFields)` (live, onBlur der Felder), `onCreate(fields: KontaktNewFields)` - **States:** Permission-Denied/Modul-gesperrt (BadgeFeedback `crm.locked.headline`) · Error (BadgeFeedback) · Duplikat-Warnung (Card `negative` bei hard / `warning` bei soft) - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: ### CustomFieldAdminPage · D-CRM "Custom-Felder", archetype A2 - **Interim-Screen:** `apps/web/app/components/screens/crm/CustomFieldAdminPage.tsx` - **Route(n):** `/app/:tenant/contacts/admin/custom-fields` (`routes/app.$tenant/contacts.admin.custom-fields.tsx`) - **Daten (VM):** `CustomFieldAdminVM` — `packages/view-models/src/crm/custom-field-admin.vm.ts` - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Button, Card, EmptyState, Select, Table, TextInput · Icons: keine - **Interaktionen (Actions):** `onCreate(input: {key, label, datentyp, optionen})`, `onArchive(definitionId: string)` - **States:** Empty (EmptyState `crm.admin.customFields.empty`) · Permission-Denied/Modul-gesperrt (BadgeFeedback `crm.locked.headline`) · Error (BadgeFeedback) - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: ### TagAdminPage · D-CRM "Tag-Verwaltung", archetype A2 - **Interim-Screen:** `apps/web/app/components/screens/crm/TagAdminPage.tsx` - **Route(n):** `/app/:tenant/contacts/admin/tags` (`routes/app.$tenant/contacts.admin.tags.tsx`) - **Daten (VM):** `TagAdminVM` (Zeilen: `TagAdminRowData`) — `packages/view-models/src/crm/tag-admin.vm.ts` - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Button, Card, EmptyState, TextInput (+ native ``, kein ~/ui-Äquivalent) · Icons: keine - **Interaktionen (Actions):** `onCreate({name, farbe})`, `onUpdate({tagId, name, farbe})`, `onDelete(tagId: string)` - **States:** Empty (EmptyState `crm.admin.tags.empty`) · Permission-Denied/Modul-gesperrt (BadgeFeedback `crm.locked.headline`) · Error (BadgeFeedback) - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: ### DuplicateToolPage · D-CRM "Duplikat-Tool", archetype A5 - **Interim-Screen:** `apps/web/app/components/screens/crm/DuplicateToolPage.tsx` - **Route(n):** `/app/:tenant/contacts/admin/duplicates` (`routes/app.$tenant/contacts.admin.duplicates.tsx`) - **Daten (VM):** `DuplicateVM` (Paare: `pair.a`/`pair.b`, `matchType` hard/soft) — `packages/view-models/src/crm/duplicate.vm.ts` - **Benötigte UI-Elemente (KEIN Layout):** BadgeFeedback, Card, EmptyState · Icons: keine - **Interaktionen (Actions):** keine (read-only; Merge folgt später, VM `canMerge=false`). Prop `detailHrefFor(kontaktId)` liefert Detail-Links - **States:** Empty (EmptyState `crm.admin.duplicates.empty`) · Permission-Denied/Modul-gesperrt (BadgeFeedback `crm.locked.headline`) - **Davids Delta (offen):** - [ ] Überschriebene/geänderte Spec-Punkte: - [ ] Neue UI/UX-Entscheidungen: - [ ] Subframe-Screen-Link(s): - [ ] Offene Fragen an Dev: