feat: Aktivitätslog tab in PropertyDetailView — per-property timeline
Adds a new "Aktivitätslog" tab (9th tab) to the supply-side property drawer. Shows match approvals/rejections, need registrations, data quality flags, and governance actions linked to this specific property. Only visible to Verwaltung users in their own property view. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,38 +33,70 @@ export interface ActivityEvent {
|
||||
organizationId: string
|
||||
notes?: string
|
||||
createdAt: string
|
||||
propertyId?: string
|
||||
}
|
||||
|
||||
const mockActivityLog: ActivityEvent[] = [
|
||||
// Day 1 — 2026-05-13
|
||||
{ id: 'evt-001', type: 'SOURCE_CRAWLED', category: 'INTELLIGENCE', entityId: 'src-001', entityType: 'SOURCE', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Baubewilligung-Feed Kanton ZH: 47 neue Einträge gefunden', createdAt: '2026-05-13T06:15:00Z' },
|
||||
{ id: 'evt-002', type: 'FUTURE_SIGNAL_DETECTED', category: 'INTELLIGENCE', entityId: 'sig-maag', entityType: 'SIGNAL', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Potenzielle Grossfläche: Maag Areal Zürich — Wahrscheinlichkeit 82%', createdAt: '2026-05-13T06:18:00Z' },
|
||||
{ id: 'evt-003', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-007', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Grundriss fehlt; Qualitätsscore 61 — unter Schwellenwert', createdAt: '2026-05-13T07:30:00Z' },
|
||||
{ id: 'evt-004', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-022', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Neues Industrieobjekt Schlieren erfasst', createdAt: '2026-05-13T09:45:00Z' },
|
||||
{ id: 'evt-003', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-007', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Grundriss fehlt; Qualitätsscore 61 — unter Schwellenwert', createdAt: '2026-05-13T07:30:00Z', propertyId: 'prop-007' },
|
||||
{ id: 'evt-004', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-022', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Neues Industrieobjekt Schlieren erfasst', createdAt: '2026-05-13T09:45:00Z', propertyId: 'prop-022' },
|
||||
// Day 2 — 2026-05-14
|
||||
{ id: 'evt-005', type: 'SOURCE_CRAWLED', category: 'INTELLIGENCE', entityId: 'src-002', entityType: 'SOURCE', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Handelsregister-Crawler: 12 Unternehmensumzüge identifiziert', createdAt: '2026-05-14T06:00:00Z' },
|
||||
{ id: 'evt-006', type: 'FUTURE_SIGNAL_DETECTED', category: 'INTELLIGENCE', entityId: 'sig-alstom', entityType: 'SIGNAL', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Alstom AG Standortanalyse — interne Dokumente verweisen auf Expansionspläne', createdAt: '2026-05-14T06:05:00Z' },
|
||||
{ id: 'evt-007', type: 'PROPERTY_UPDATED', category: 'GOVERNANCE', entityId: 'prop-003', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Verfügbarkeit aktualisiert: sofort verfügbar', createdAt: '2026-05-14T10:20:00Z' },
|
||||
{ id: 'evt-007', type: 'PROPERTY_UPDATED', category: 'GOVERNANCE', entityId: 'prop-003', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Verfügbarkeit aktualisiert: sofort verfügbar', createdAt: '2026-05-14T10:20:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'evt-008', type: 'REVIEW_REQUESTED', category: 'REVIEW', entityId: 'ai-out-003', entityType: 'AI_OUTPUT', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Need-Parse-Output zur manuellen Prüfung eingereicht', createdAt: '2026-05-14T14:00:00Z' },
|
||||
{ id: 'evt-009', type: 'AI_OUTPUT_REVIEWED', category: 'REVIEW', entityId: 'ai-out-003', entityType: 'AI_OUTPUT', performedBy: 'reviewer@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Output genehmigt — Kriterienextraktion korrekt', createdAt: '2026-05-14T15:30:00Z' },
|
||||
// Day 3 — 2026-05-15
|
||||
{ id: 'evt-010', type: 'NEED_CREATED', category: 'SUCHE', entityId: 'need-042', entityType: 'NEED', performedBy: 'demand@globocorp.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Natürlichsprachliche Suche: "2500m² Büro Zürich West, offen, Rep.'+ "'" + 'resentanz-qualität"', createdAt: '2026-05-15T09:10:00Z' },
|
||||
{ id: 'evt-010', type: 'NEED_CREATED', category: 'SUCHE', entityId: 'need-042', entityType: 'NEED', performedBy: 'demand@globocorp.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Natürlichsprachliche Suche: "2500m² Büro Zürich West, offen, Repräsentanz-qualität"', createdAt: '2026-05-15T09:10:00Z' },
|
||||
{ id: 'evt-011', type: 'AI_PARSE_COMPLETED', category: 'SUCHE', entityId: 'need-042', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Konfidenz 87% — Kriterien: OFFICE 2000–3000m², Zürich West, CHF 280/m², Einzug Q3 2026', createdAt: '2026-05-15T09:10:04Z' },
|
||||
{ id: 'evt-012', type: 'MATCH_GENERATED', category: 'MATCHING', entityId: 'need-042', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: '14 Kandidaten bewertet — 3 STARK (≥80), 6 MITTEL, 5 SCHWACH', createdAt: '2026-05-15T09:10:07Z' },
|
||||
{ id: 'evt-013', type: 'SIGNAL_VERIFIED', category: 'INTELLIGENCE', entityId: 'sig-maag', entityType: 'SIGNAL', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Maag Areal Signal verifiziert — Baubewilligung bestätigt', createdAt: '2026-05-15T10:00:00Z' },
|
||||
{ id: 'evt-014', type: 'SHORTLIST_CREATED', category: 'SUCHE', entityId: 'sl-globo-01', entityType: 'SHORTLIST', performedBy: 'demand@globocorp.ch', isAiAction: false, organizationId: 'org-wincasa', notes: '4 Objekte auf Shortlist "Zürich West Q3 2026"', createdAt: '2026-05-15T11:45:00Z' },
|
||||
{ id: 'evt-015', type: 'FUTURE_SIGNAL_CONVERTED', category: 'INTELLIGENCE', entityId: 'sig-maag', entityType: 'SIGNAL', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Signal in zukünftige Verfügbarkeit umgewandelt — erscheint im Unified Feed', createdAt: '2026-05-15T13:00:00Z' },
|
||||
// Day 4 — 2026-05-16
|
||||
{ id: 'evt-016', type: 'MATCH_APPROVED', category: 'MATCHING', entityId: 'match-003', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 91 — Starker Match Hardturmstrasse 201 × GloboCorp bestätigt', createdAt: '2026-05-16T09:00:00Z' },
|
||||
{ id: 'evt-016', type: 'MATCH_APPROVED', category: 'MATCHING', entityId: 'match-003', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 91 — Starker Match Hardturmstrasse 201 × GloboCorp bestätigt', createdAt: '2026-05-16T09:00:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'evt-017', type: 'REVIEW_REQUESTED', category: 'REVIEW', entityId: 'sig-alstom', entityType: 'SIGNAL', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Vertrauliches Signal zur Governance-Prüfung eingereicht', createdAt: '2026-05-16T10:15:00Z' },
|
||||
{ id: 'evt-018', type: 'DECISION_BRIEF_CREATED', category: 'SUCHE', entityId: 'sl-globo-01', entityType: 'SHORTLIST', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'KI-Entscheidungsbriefing für Shortlist generiert — Empfehlung: Hardturmstrasse 201', createdAt: '2026-05-16T11:30:00Z' },
|
||||
{ id: 'evt-018', type: 'DECISION_BRIEF_CREATED', category: 'SUCHE', entityId: 'sl-globo-01', entityType: 'SHORTLIST', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'KI-Entscheidungsbriefing für Shortlist generiert — Empfehlung: Hardturmstrasse 201', createdAt: '2026-05-16T11:30:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'evt-019', type: 'REVIEW_COMPLETED', category: 'REVIEW', entityId: 'sig-alstom', entityType: 'SIGNAL', performedBy: 'reviewer@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'GENEHMIGT — Vertraulichkeitsstufe bestätigt, Signal für Demand-Pipeline freigegeben', createdAt: '2026-05-16T14:00:00Z' },
|
||||
{ id: 'evt-020', type: 'SHORTLIST_FINALIZED', category: 'SUCHE', entityId: 'sl-globo-01', entityType: 'SHORTLIST', performedBy: 'demand@globocorp.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Shortlist finalisiert — Kundenentscheid: Objekt 1 und 3 zur Besichtigung', createdAt: '2026-05-16T16:45:00Z' },
|
||||
// Day 5 — 2026-05-17 (heute)
|
||||
// Day 5 — 2026-05-17
|
||||
{ id: 'evt-021', type: 'SOURCE_CRAWLED', category: 'INTELLIGENCE', entityId: 'src-003', entityType: 'SOURCE', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'LinkedIn-Jobpostings-Crawler: 8 Expansionssignale gefunden', createdAt: '2026-05-17T06:00:00Z' },
|
||||
{ id: 'evt-022', type: 'FUTURE_SIGNAL_DETECTED', category: 'INTELLIGENCE', entityId: 'sig-novartis', entityType: 'SIGNAL', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Novartis Basel: 47 Stelleninserate für "Basel Life Sciences Hub" — Flächensignal', createdAt: '2026-05-17T06:12:00Z' },
|
||||
{ id: 'evt-023', type: 'MATCH_REJECTED', category: 'MATCHING', entityId: 'match-009', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 64 — zu schwach, manuell abgelehnt', createdAt: '2026-05-17T08:30:00Z' },
|
||||
{ id: 'evt-024', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-015', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Preisangabe 18 Monate alt — automatische Qualitätswarnung', createdAt: '2026-05-17T09:00:00Z' },
|
||||
{ id: 'evt-023', type: 'MATCH_REJECTED', category: 'MATCHING', entityId: 'match-009', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 64 — zu schwach, manuell abgelehnt', createdAt: '2026-05-17T08:30:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'evt-024', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-015', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Preisangabe 18 Monate alt — automatische Qualitätswarnung', createdAt: '2026-05-17T09:00:00Z', propertyId: 'prop-015' },
|
||||
|
||||
// ── Property-specific events (visible in per-property activity log) ───────────
|
||||
// prop-001
|
||||
{ id: 'p1-001', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-001', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Bürofläche Hardturmstrasse 201 neu erfasst', createdAt: '2026-04-02T09:00:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'p1-002', type: 'MATCH_GENERATED', category: 'MATCHING', entityId: 'need-031', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Score 91 — Bedarf GloboCorp: sehr starke Übereinstimmung bei Fläche, Lage, Einzugstermin', createdAt: '2026-05-10T08:14:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'p1-003', type: 'NEED_CREATED', category: 'SUCHE', entityId: 'need-039', entityType: 'NEED', performedBy: 'demand@helvetia.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Helvetia Versicherungen: Bedarf 1800m² Büro Zürich West — Objekt als Kandidat vorgemerkt', createdAt: '2026-05-12T10:30:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'p1-004', type: 'MATCH_APPROVED', category: 'MATCHING', entityId: 'match-003', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Match GloboCorp genehmigt — Besichtigung vereinbart für 20.05.2026', createdAt: '2026-05-16T09:00:00Z', propertyId: 'prop-001' },
|
||||
{ id: 'p1-005', type: 'MATCH_REJECTED', category: 'MATCHING', entityId: 'match-011', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 71 — Miete über Budget des Interessenten, abgelehnt', createdAt: '2026-05-17T11:00:00Z', propertyId: 'prop-001' },
|
||||
|
||||
// prop-003
|
||||
{ id: 'p3-001', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-003', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Logistikfläche Pratteln initial erfasst', createdAt: '2026-03-15T08:30:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'p3-002', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-003', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Laderampen-Anzahl fehlt; Deckenhöhe nicht angegeben — Score 68', createdAt: '2026-04-10T07:45:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'p3-003', type: 'PROPERTY_UPDATED', category: 'GOVERNANCE', entityId: 'prop-003', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Verfügbarkeit aktualisiert: sofort verfügbar, Laderampen und Deckenhöhe ergänzt', createdAt: '2026-05-14T10:20:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'p3-004', type: 'MATCH_GENERATED', category: 'MATCHING', entityId: 'need-044', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: '3 Bedarfe ausgewertet — Score-Spanne 64–78, kein STARK-Match', createdAt: '2026-05-15T14:20:00Z', propertyId: 'prop-003' },
|
||||
{ id: 'p3-005', type: 'MATCH_REJECTED', category: 'MATCHING', entityId: 'match-009', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Score 64 — zu schwach, manuell abgelehnt', createdAt: '2026-05-17T08:30:00Z', propertyId: 'prop-003' },
|
||||
|
||||
// prop-007
|
||||
{ id: 'p7-001', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-007', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Retail-Fläche Basel Steinenvorstadt erfasst', createdAt: '2026-02-28T11:00:00Z', propertyId: 'prop-007' },
|
||||
{ id: 'p7-002', type: 'MATCH_GENERATED', category: 'MATCHING', entityId: 'need-037', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Score 83 — Bedarf Retail-Kette Innenstadt Basel: guter Match', createdAt: '2026-04-20T09:30:00Z', propertyId: 'prop-007' },
|
||||
{ id: 'p7-003', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-007', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Grundriss fehlt; Qualitätsscore 61 — unter Schwellenwert', createdAt: '2026-05-13T07:30:00Z', propertyId: 'prop-007' },
|
||||
|
||||
// prop-014
|
||||
{ id: 'p14-001', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-014', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Logistikhalle Pratteln erfasst', createdAt: '2026-01-10T09:00:00Z', propertyId: 'prop-014' },
|
||||
{ id: 'p14-002', type: 'MATCH_GENERATED', category: 'MATCHING', entityId: 'need-040', entityType: 'NEED', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Score 88 — Bedarf Logistik-Unternehmen: starke Übereinstimmung', createdAt: '2026-04-28T10:15:00Z', propertyId: 'prop-014' },
|
||||
{ id: 'p14-003', type: 'REVIEW_REQUESTED', category: 'REVIEW', entityId: 'match-014', entityType: 'MATCH', performedBy: 'admin@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Match zur Governance-Prüfung eingereicht — Interessent aus EU-Ausland', createdAt: '2026-05-05T13:00:00Z', propertyId: 'prop-014' },
|
||||
{ id: 'p14-004', type: 'REVIEW_COMPLETED', category: 'REVIEW', entityId: 'match-014', entityType: 'MATCH', performedBy: 'reviewer@ideal-sharing.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'GENEHMIGT — Bonitätsprüfung bestanden, Match freigegeben', createdAt: '2026-05-07T15:30:00Z', propertyId: 'prop-014' },
|
||||
|
||||
// prop-015
|
||||
{ id: 'p15-001', type: 'PROPERTY_CREATED', category: 'GOVERNANCE', entityId: 'prop-015', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Bürofläche Zürich Oerlikon erfasst', createdAt: '2026-02-01T10:00:00Z', propertyId: 'prop-015' },
|
||||
{ id: 'p15-002', type: 'PROPERTY_UPDATED', category: 'GOVERNANCE', entityId: 'prop-015', entityType: 'PROPERTY', performedBy: 'manager@wincasa.ch', isAiAction: false, organizationId: 'org-wincasa', notes: 'Mietpreis angepasst: CHF 195 → 210/m²/Jahr', createdAt: '2026-03-18T14:30:00Z', propertyId: 'prop-015' },
|
||||
{ id: 'p15-003', type: 'DATA_QUALITY_FLAGGED', category: 'GOVERNANCE', entityId: 'prop-015', entityType: 'PROPERTY', performedBy: 'system@property-match', isAiAction: true, organizationId: 'org-wincasa', notes: 'Preisangabe 18 Monate alt — automatische Qualitätswarnung', createdAt: '2026-05-17T09:00:00Z', propertyId: 'prop-015' },
|
||||
]
|
||||
|
||||
const store = [...mockActivityLog]
|
||||
@@ -74,6 +106,10 @@ export const governanceService = {
|
||||
const data = organizationId ? store.filter(e => e.organizationId === organizationId) : [...store]
|
||||
return { data: data.sort((a, b) => b.createdAt.localeCompare(a.createdAt)), meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
|
||||
},
|
||||
async getActivityLogByProperty(propertyId: string): Promise<ListResponse<ActivityEvent>> {
|
||||
const data = store.filter(e => e.propertyId === propertyId)
|
||||
return { data: data.sort((a, b) => b.createdAt.localeCompare(a.createdAt)), meta: { total: data.length, page: 1, pageSize: data.length, hasMore: false } }
|
||||
},
|
||||
async logEvent(event: Omit<ActivityEvent, 'id' | 'createdAt'>): Promise<ItemResponse<ActivityEvent>> {
|
||||
const data: ActivityEvent = { id: crypto.randomUUID(), ...event, createdAt: new Date().toISOString() }
|
||||
store.push(data)
|
||||
|
||||
Reference in New Issue
Block a user