Framework CRM Activity Signals

Candidate Activity &
Messaging Framework

Ziel ist nicht nur bessere Analytics, sondern eine operative Activity-Layer für den ganzen Candidate Lifecycle: Wer ist aktiv, wer wird gerade warm, wer ist veraltet, wer reagiert auf Newsletter, und wann ist der beste Moment für Reverse Apply, Active Sourcing oder Reaktivierung?

Kernidee: Das Backend bleibt System of Record für Kandidaten, Matches und Messaging-Ausspielung. BigQuery wird System of Record für rohe Aktivitäts-Events und historische Feature-Berechnung. Ein abgeleitetes Candidate Activity Profile wird zurück ins Backend synchronisiert und von CRM, Newsletter, Reverse Apply und später Active Sourcing konsumiert.

Current State im Backend

Aus der aktuellen Codebasis sieht man schon gute operative Bausteine, aber noch keine echte Event-Architektur.

Candidate State

Applier enthält bereits Präferenzen, Qualifikation, job_search_status, Dringlichkeit, Gehalt, Weiterbildung und historische Marker wie is_historical.

Lifecycle & CRM

ApplierHistory und match.History bilden operative History, Aufgaben, Statuswechsel und Kommunikations-Events bereits ab.

Messaging

Newsletter-Selektion läuft heute überwiegend über Match-Daten und Filters in apps/match/utils.py; Unsubs liegen in MessageUnsubscription.

Wichtige Beobachtung

In der inspizierten Backend-Codebasis ist aktuell kein sichtbarer zentraler Raw-Event-Stream und auch keine sichtbare BigQuery-Pipeline für Candidate Activity zu erkennen. Es gibt operative Daten, aber keine durchgehende Activity-Historie über App-Nutzung, CRM-Engagement und Messaging-Reaktionen.

Discovery-Signale fachlich vorhanden

Für Salary- und Distanzsignale gibt es bereits gute Backend-Anker: SalaryEstimates wird über den ConstantsApiView ausgeliefert, und im Matching werden distance und duration pro Match berechnet und gespeichert. Nicht sichtbar gefunden habe ich bislang aber keine expliziten User-Events, die die Nutzung eines Gehalts- oder Distanz-Tools schon mitschreiben. Deshalb sollten diese Signale im Framework als neu zu instrumentierende Discovery-Events behandelt werden.

Production Ready Applicants App Dual Ingestion (PubSub + PostHog)

Implementierte Events in der Applicants App

Übersicht aller aktuell im Frontend (laenk-applicant-app-v2) umgesetzten Events. Jedes Event wird automatisch mit den Top-Level Schema-Feldern angereichert (app_name = "applicants", session_id, is_logged_in, user_agent) und per Dual-Send parallel an PubSub (Cloud Run → BigQuery) sowie PostHog Analytics übertragen.

Multi-App Identification

Jedes Payload enthält app_name: "applicants" zur sauberen Trennung in BigQuery bei künftigen Multi-App-Streams.

Session Tracking

Organisiert über session_id (UUID in sessionStorage). Bleibt über die gesamte Browser-Sitzung konstant.

Dynamic Auth & Device State

Stellt is_logged_in (dynamisch per Event) und user_agent (navigator.userAgent) auf oberster Ebene bereit.

Retry & Deduplication

Nutzt idempotency_key zur Duplikat-Vermeidung bei HTTP-Retries in Cloud Run und Ingestion Endpoints.

Domain Event Name Beschreibung & Triggermoment Metadaten (Metadata Payload)
App & Session app_opened Technical App Launch: Feuert bei jedem Anwendungs-Boot/Seitenload. Misst Bildschirmauflösung und Browserumgebung. screen_resolution, user_agent
session_started Session Entry: Feuert exakt 1x pro neuer session_id (UUID-Erstellung im sessionStorage). Misst Erst-Referrer und Entry. referrer
nav_tab_switched Oberflächen-Wechsel: Feuert bei Klick auf Haupt-Tabs (Jobs vs. Profil) in der Bottom Nav oder Desktop Nav. tab_name ("jobs" | "profile")
Job Discovery job_list_viewed Such- & Feed-Aufruf: Misst Trefferanzahl und Filter-Veränderung im Job-Feed. total_jobs_count, filtered_jobs_count
job_viewed Job Detail Impression: Aufruf einer konkreten Stellenausschreibung / Match-Karte. job_id, company_id, match_id, journey_context
job_saved Merken: Kandidat speichert/lesezeichenisiert eine Stelle. job_id, company_id, match_id
job_unsaved Entfernen: Kandidat entfernt gemerkte Stelle. job_id, company_id, match_id
filter_changed Filter-Anpassung: Ändern von aktiven Such- oder Match-Filtern im Feed. filters (Record mit aktiven Filterkriterien)
search_area_changed Suchradius: Ändern von Umkreis-Entfernung, PLZ oder Stadt. max_distance, postcode, city
job_ask_question_clicked Rückfrage: Klick auf den "Fragen"-Button auf der Job-Detailseite. job_id, company_id, match_id
job_calculate_travel_time_clicked Fahrzeit-Tool: Klick auf "Genaue Fahrzeit berechnen" auf der Job-Detailseite. job_id, company_id, match_id
job_calculate_salary_clicked Gehalts-Tool: Klick auf "Ungefähres Gehalt berechnen" auf der Job-Detailseite. job_id, company_id, match_id
job_interest_cta_clicked Bewerbungs-Start: Klick auf "Ich bin interessiert!" Haupt-CTA auf der Job-Detailseite (öffnet Modal). job_id, company_id, match_id, cta_location: "job_details_page"
job_interest_modal_cancelled Bewerbungs-Abbrechen: Klick auf "Abbrechen" im Bestätigungs-Modal. job_id, company_id, match_id, cta_location: "confirmation_modal"
job_interest_modal_confirmed Bewerbungs-Abschluss: Klick auf "Ich bin interessiert!" im Bestätigungs-Modal (sendet Bewerbung). job_id, company_id, match_id, cta_location: "confirmation_modal", list_position
Profile Surface profile_viewed Profil-Aufruf: Aufruf der Profil-Landingpage. journey_context (z.B. "direct_navigation")
profile_section_viewed Sektions-Anzeige: Kandidat betritt/sieht eine konkrete Profil-Sektion im Edit-Sheet oder Wizard. section_key, section_label, mode ("single" | "wizard")
profile_completion_flow_viewed Campaign Landing Impression: Aufruf der Profil-Vervollständigungs-Landingpage ("Hey [Name], mach dein Profil fit"). source ("profile_card" | "deeplink")
profile_completion_flow_started Wizard Start: Klick auf "Profil vervollständigen" in der Landingpage zum Start des interaktiven Assistenten. source ("landing_banner")
profile_completion_flow_dismissed Abbrechen/Schließen: Klick auf den Zurück-Pfeil oder "Später — zum Profil" in der Landingpage. source ("campaign_landing")
company_view_preview_clicked Unternehmensansicht: Klick auf "Unternehmensansicht ansehen" CTA. source ("visibility_card" | "profile_header")
profile_wizard_step_skipped Wizard Überspringen: Klick auf "Überspringen" bei einem missing step im Vervollständigungs-Wizard. step_key, step_index, total_steps
profile_wizard_back_clicked Wizard Zurück: Klick auf den Zurück-Pfeil im Vervollständigungs-Wizard zur vorherigen Seite. current_step_key, target_step_key, current_index
profile_wizard_completed Wizard Abschluss: Beenden des Vervollständigungs-Wizard (alle Schritte gelöst vs. Incomplete-Summary). outcome ("success" | "incomplete"), total_steps_completed, total_steps
profile_updated Generisches Update-Fallback bei sonstigen allgemeinen Profiländerungen. section_key, section_label
Status & Visibility job_search_status_updated Suchstatus-Update: Aktualisierung des Jobsuche-Status (aktiv, offen, nicht suchend) und Dringlichkeit. Single Source of Truth im JobSearchStatusService. section_key: "jobSearchStatus", status, urgency
active_sourcing_visibility_updated Sichtbarkeits-Toggle: Ein-/Ausschalten der anonymen Sichtbarkeit für Arbeitgeber (Reverse Recruiting / Active Sourcing). is_reverse_recruiting_enabled (boolean)
Preferences shift_preferences_updated Schichtpräferenz: Speichern von Schichtmodellen (Früh, Spät, Nacht, Wochenende). section_key: "shiftPreferences", section_label: "Schichtpräferenz"
working_hours_updated Dienstlänge: Speichern der wöchentlichen Arbeitsstunden / Schichtdauer. section_key: "shiftHour", section_label: "Dienstlänge"
working_type_updated Arbeitsumfang: Speichern von Vollzeit / Teilzeit / Minijob. section_key: "workingType", section_label: "Arbeitsumfang"
position_updated Position: Speichern der gewünschten Berufsbezeichnung / Fachposition. section_key: "position", section_label: "Position"
care_type_updated Einrichtungsarten: Speichern von Krankenhaus, Altenpflege, Ambulant etc. section_key: "careType", section_label: "Einrichtungsarten"
Qualification education_updated Ausbildung: Speichern von Berufsabschluss / Qualifikation. section_key: "education", section_label: "Ausbildung"
continuing_education_updated Weiterbildung: Speichern von Fachweiterbildungen / Zertifikaten. section_key: "continuingEducation", section_label: "Weiterbildungen"
driving_license_updated Führerschein: Speichern von Führerscheinklassen (PKW, LKW). section_key: "driving_license", section_label: "Führerschein"
language_skill_updated Sprachkenntnisse: Speichern von Sprachen und Sprachniveau. section_key: "language", section_label: "Sprachkenntnisse"
personal_data_updated Persönliches: Speichern von persönlichen Stammdaten (ohne PII Klartext). section_key: "personal", section_label: "Persönliches"
document_uploaded Dokumenten-Upload: Speichern von Lebenslauf (RESUME), Urkunden, Zertifikaten oder Nachweisen. source ("PROFILE" | "APPLY-SCREEN"), file_types, file_count

1. Event Tracking

Das Eventmodell sollte entlang der Candidate Journey strukturiert werden. So bleibt es verständlich, erweiterbar und operativ verwertbar.

Domain Core Events Warum relevant
App & Session app_opened, session_started Minimales Grundsignal für Recency und Basisaktivität, ohne schon zu viel generisches Event-Rauschen zu erzeugen.
Job Discovery job_list_viewed, job_viewed, job_saved, job_unsaved, filter_changed, search_area_changed, job_ask_question_clicked, job_calculate_travel_time_clicked, job_calculate_salary_clicked, job_interest_cta_clicked, job_interest_modal_cancelled, job_interest_modal_confirmed Zeigt Suchintensität, Präferenz-Drift und den Übergang von reiner Exploration zu echter Bewerbungsabsicht. Dazu gehören auch Tools, mit denen Kandidaten prüfen, ob sich ein Job finanziell oder vom Arbeitsweg her lohnt.
Profile Surface profile_viewed, profile_updated Generische Oberflächen-Events für die gesamte Profilansicht. Hilfreich für Usage und Funnel-Verständnis, aber bewusst getrennt von den fachlichen Feld-Signalen.
Status & Visibility job_search_status_updated, job_search_urgency_updated, start_date_updated, active_sourcing_visibility_updated Hochdynamische Steuerungssignale für CRM, Reaktivierung, Outreach und spätere Active-Sourcing-Freigaben.
Preferences care_type_updated, position_updated, search_area_updated, working_type_updated, shift_preferences_updated, working_hours_updated Entspricht den Merkmalsfeldern aus der Präferenz-Zone in Experiment 18, nur ohne Verfügbarkeit: Einrichtungsarten, gesuchte Position, Standort, Arbeitsumfang, Dienst-Präferenzen und bevorzugte Arbeitszeit. Genau diese Felder sollten zyklisch durch CRM bestätigt oder aktualisiert werden.
Qualification education_updated, continuing_education_updated, specialization_updated, language_skill_updated, driving_license_updated, work_experience_updated, work_history_updated, cv_uploaded, document_uploaded Eher langsam veränderliche Eignungs- und Nachweisfelder. Wichtig für Profilqualität, Matching und spätere Eignungsfilter.
CRM Engagement newsletter_sent, newsletter_opened, newsletter_clicked, whatsapp_sent, whatsapp_clicked, push_opened, unsubscribe_changed Misst Responsiveness und Kanalpräferenz.

Journey Context

Zusätzlich zur fachlichen Event-Domain sollten wir festhalten, in welchem Produktkontext ein Verhalten oder Update passiert ist. So sehen wir später nicht nur was geändert wurde, sondern auch wie es dazu kam.

Wofür wird das gebraucht?

  • Um organische Profilpflege von CRM- oder Flow-getriebenen Updates zu unterscheiden.
  • Um später zu analysieren, welche Journeys die beste Profilqualität oder die beste Aktivierung erzeugen.
  • Um Messaging-Trigger sauber mit nachgelagertem Verhalten zu verbinden.
Journey Context Wann wird es gesetzt? Beispiele
standalone_profile_edit Wenn ein Kandidat direkt im Profil einzelne Daten bearbeitet. search_area_updated, education_updated
profile_completion_flow Wenn ein Update im Profilvervollständigungs-Flow passiert. continuing_education_updated, shift_preferences_updated
preference_refresh_flow Wenn Präferenzen zyklisch erneut abgefragt oder bestätigt werden. working_type_updated, care_type_updated
email_reactivation Wenn ein Kandidat aus einer Reaktivierungs-Mail zurückkommt und dann handelt. app_opened, job_viewed, profile_completion_flow_started
crm_prompt Wenn das Verhalten aus einem In-App- oder Backend-getriggerten CRM-Hinweis kommt. job_search_status_updated, salary_tool_used
job_feed Wenn das Verhalten aus der normalen Jobsuche bzw. Feed-Nutzung stammt. job_list_viewed, job_saved, commute_calculated

Beispiel

Wenn ein Kandidat im Profilvervollständigungs-Flow seine Weiterbildung ergänzt, speichern wir fachlich event_domain = qualification und zusätzlich journey_context = profile_completion_flow. So bleibt die inhaltliche Änderung sauber klassifiziert, und gleichzeitig bleibt die Herkunft des Updates erhalten.

2. Event Schema

Ich würde ein einziges kanonisches Event-Schema definieren und pro Event nur unterschiedliche Payloads zulassen. Sonst explodieren später BigQuery, dbt und CRM-Logik.

Feld Typ Pflicht? Beschreibung
event_idUUIDJaEindeutige Event-ID für Dedupe und Replay.
event_namestringJaZ. B. job_viewed oder newsletter_clicked.
event_domainstringJaApp & Session, Job Discovery, Profile Surface, Status & Visibility, Preferences, Qualification, CRM.
occurred_attimestampJaZeitpunkt des Nutzerverhaltens (ISO 8601 UTC).
ingested_attimestampJaZeitpunkt der technischen Annahme in der Pipeline (ISO 8601 UTC).
app_namestringJaPrimärer App-Identifier (z. B. "applicants") zur eindeutigen Zuordnung in Multi-App-BigQuery-Streams.
is_logged_inbooleanJaDynamischer Authentifizierungs-Status des Kandidaten im Augenblick der Event-Ausführung.
user_agentstringJaBrowser- & Gerätekennung des Nutzers (navigator.userAgent) für technische Analytics und Device-Segmentierung.
candidate_user_idint | stringJa*Primäre Candidate-ID; bei anonymen Events kann zunächst nur eine device/session ID vorliegen.
candidate_applier_idint | stringOptionalWenn Event auf konkretem Applier-Datensatz statt nur User liegt.
session_idstring (UUID)JaVerbindet einzelne Screen- und Click-Events innerhalb einer kontinuierlichen Sitzung (in sessionStorage gespeichert).
journey_contextstringOptionalProdukt- oder Triggerkontext, in dem das Event passiert ist, z. B. profile_completion_flow, standalone_profile_edit, preference_refresh_flow, job_feed.
sourcestringJaNur technischer Ursprung des Events: web, app, backend, crm, whatsapp, sendgrid.
channelstringOptionalEmail, Push, WhatsApp, In-App, Backend-Automation.
job_idint | stringOptionalWenn das Event an einem Job hängt.
company_idint | stringOptionalWenn das Event an einem Unternehmen hängt.
match_idint | stringOptionalWenn das Event aus Match-/Reverse-Apply-Logik kommt.
campaign_idstringOptionalInterne eindeutige Kampagnen-ID für CRM, Reverse Apply, Reaktivierung oder Paid Acquisition.
campaign_typestringOptionalZ. B. newsletter, reverse_apply, reactivation, active_sourcing, paid_acquisition.
campaign_namestringOptionalLesbarer Kampagnenname für CRM, Reporting und Debugging.
utm_source, utm_medium, utm_campaignstringOptionalNur für echte Link-Attribution bei Web-/Email-/WhatsApp-Einstiegen; nicht als primäres Kampagnenmodell missbrauchen.
campaign_keywordstringOptionalLegacy-/Brückenfeld, falls bestehende Backend-Logik oder Heyflow-Importe dieses Label weiter benutzen.
metadataJSONJaEvent-spezifische Details wie Sektions-Keys, alte/neue Werte, Wizard-Fortschritt, Filter etc.
idempotency_keystringJaDeduplizierungs-Schlüssel (defaults to event_id) zur Vermeidung von Mehrfachverarbeitung bei HTTP-Retries in Cloud Run.

Empfohlene Vereinfachung

source beschreibt nur, wo das Event technisch herkommt. campaign_id, campaign_type und optional utm_* beschreiben dagegen den Messaging- oder Acquisition-Kontext. So vermeiden wir, dass technische Herkunft und Kampagnenlogik miteinander vermischt werden.

Feld-Level Events oder nur profile_updated?

Ja, ich würde relevante Merkmale auf Feld-Ebene tracken und nicht nur ein generisches profile_updated. Sonst verliert ihr genau den Mehrwert, später zu verstehen, welche Präferenzen und Qualifikationen sich häufig ändern und welche Signalgruppen für CRM wirklich funktionieren.

  • Pflicht auf Feld-Ebene: alles, was Matching, Messaging oder Active Sourcing direkt beeinflusst.
  • Nur generisch: rein kosmetische Änderungen wie Profilbild, Freitext ohne klare operative Nutzung oder UI-only Änderungen.
  • Praktische Regel: Wenn ein Feld später Segmentierung, Priorisierung, Ausspielung oder Scoring beeinflussen kann, bekommt es ein eigenes Event.

3. Data Flow

Event Origination

  • Frontend/App feuert UI- und Engagement-Events.
  • Backend & Frontend feuern State-Change- & Action-Events wie job_interest_modal_confirmed, job_search_status_updated, newsletter_sent.
  • CRM-Provider schicken Delivery-, Open- und Click-Events zurück.

Storage Layers

  • Raw event store mit append-only Verhalten.
  • BigQuery raw tables partitioniert nach occurred_at.
  • Feature tables mit 1 Zeile pro Candidate.
  • Operational backend table für synchronisierte Activity Features.

Empfohlene End-to-End-Architektur

  1. Frontend, Backend und Messaging-Provider senden Events in einen zentralen Ingestion-Layer.
  2. Dieser schreibt jedes Event unverändert in einen Raw Store und parallel nach BigQuery.
  3. BigQuery baut daraus saubere modellierte Tabellen: Sessions, CRM Engagement, Applications, Profile Changes, Search Intent.
  4. Stündliche oder tägliche Feature-Jobs berechnen Candidate Activity Features.
  5. Eine dedizierte Sync-Stufe schreibt nur die operativ benötigten Features zurück ins Backend.
  6. Messaging liest nicht direkt aus Raw Events, sondern aus dem synchronisierten Activity Profile plus Consent/Operational State.

4. Candidate Activity Profile

Pro Candidate sollte es genau ein abgeleitetes Activity Profile geben, das schnell im Backend konsumierbar ist.

Recency & Engagement

last_active_at, last_job_view_at, last_profile_update_at, sessions_7d, sessions_30d, job_views_7d, job_views_30d

Application Intent

applications_7d, applications_30d, applications_started_30d, reverse_apply_clicks_30d, interested_matches_30d

CRM Responsiveness

newsletter_opens_30d, newsletter_clicks_30d, whatsapp_clicks_30d, push_opens_30d, last_channel_engaged

Profile Freshness

profile_completeness_score, preference_freshness_days, qualification_freshness_days, job_search_status_age_days

Operational Flags

active_last_30d, dormant_90d, high_intent, warm_for_reactivation, eligible_for_active_sourcing

Intent Scaffolding

search_intent_score, candidate_health_score, message_fatigue_score, predicted_response_probability

5. Ownership

Backend

  • Operative Candidate-Profile
  • Consent / Messaging Permissions
  • Messaging-Ausspielung
  • Synchronisierte Activity Flags

BigQuery

  • Raw Events
  • Historische Aggregationen
  • Feature Computation
  • Training Data für Scores/ML

Analytics / CRM

  • Dashboards
  • Segmentdefinitionen
  • Experiment-Auswertung
  • Message Strategy

6. Synchronization

Meine Empfehlung ist ein hybrides Modell:

  • Event-driven sofort: heiße Flags wie last_active_at, job_search_status_updated_at, high_intent nach einer Bewerbung oder einem Reverse-Apply-Click.
  • Stündlicher Batch: Rolling Windows wie job_views_7d, newsletter_clicks_30d, applications_30d.
  • Täglicher Batch: schwerere Scores wie Search Intent Score, Candidate Health Score, Messaging Fatigue und Pro/AS Eligibility.

So bleibt das Backend schlank, aber die operativ wichtigen Dinge werden schnell genug aktualisiert.

7. Messaging Integration

Newsletter

Nicht mehr nur statische Fit-Daten. Stattdessen: offene Kandidaten mit frischen Präferenzen, guter Newsletter-Responsiveness und ohne hohe Message Fatigue.

Reverse Apply

Nur Kandidaten mit hoher Suchintention, recent activity oder bestätigtem Suchstatus. Kein aggressives Pingen bei Schlafenden.

Active Sourcing

Unternehmen sehen nur Kandidaten mit AS-Consent, ausreichender Profilqualität und Activity-Signalen, die auf echte Bereitschaft hindeuten.

Push / Email / WhatsApp

Kanäle werden über last_channel_engaged, Click-Rates und Unsub-Verhalten priorisiert. Ziel: weniger Spam, mehr Relevanz.

Segment-Beispiele

  • Hot Searchers: aktiv in den letzten 7 Tagen, Job Views hoch, Reverse Apply oder Bewerbungsstart vorhanden.
  • Warm Passive: Status offen, letzte Aktivität < 30 Tage, klickt Newsletter, aber bewirbt sich wenig.
  • Stale but Recoverable: keine Aktivität 90+ Tage, aber historisch gute Responsiveness oder hohe Fit-Potenziale.
  • Active-Sourcing Ready: Profilqualität hoch, Consent vorhanden, Status aktiv/offen, keine negativen Privacy-Signale.

8. Future-proof Design

Search Intent Score

Wird aus Session-Recency, Job Views, Preference Updates, Applications und Reverse-Apply-Engagement gelernt.

Candidate Health Score

Kombiniert Datenfrische, Matchbarkeit, Responsiveness, Consent und Channel Reachability.

AI Messaging

Personalisierte Prompts und Message-Texte können später sicher auf denselben standardisierten Features aufsetzen.

Customer-facing Active Sourcing

Die gleiche Activity-Layer entscheidet später, welche Kandidaten im Unternehmensprodukt sichtbar, priorisiert oder ausgeblendet werden.

Schwächen der aktuellen Architektur

  • Zu statisch: Newsletter- und Outreach-Logik schaut heute primär auf Profil-/Match-Zustand, nicht auf echtes Verhalten.
  • Kein Raw Event Layer: Ohne vollständige Eventhistorie fehlen saubere Rolling Windows, Funnel-Abbrüche und Channel-Effekte.
  • Zu viel Logik im Operational Backend: Gut für Produkt, aber nicht ideal für historische Analyse und schnelle Experimentation.
  • Keine klare Trennung zwischen Operational State und Computed Activity Features.
  • Kein standardisiertes Candidate Activity Profile, das alle Messaging-Kanäle gemeinsam nutzen.

MVP Event Proposal zur Bestätigung

Damit wir nicht zu breit starten, würde ich für V1 diese Events wirklich als Pflichtset empfehlen:

  1. App & Session: app_opened, session_started
  2. Discovery & Apply: job_list_viewed, job_viewed, job_saved, filter_changed, job_ask_question_clicked, job_calculate_travel_time_clicked, job_calculate_salary_clicked, job_interest_cta_clicked, job_interest_modal_cancelled, job_interest_modal_confirmed
  3. Intent Signals: reverse_apply_clicked, match_marked_interested
  4. Profile Surface: profile_viewed, profile_updated
  5. Status & Visibility: job_search_status_updated, job_search_urgency_updated, start_date_updated, active_sourcing_visibility_updated
  6. Preferences: care_type_updated, position_updated, search_area_updated, working_type_updated, shift_preferences_updated, working_hours_updated
  7. Qualification: education_updated, continuing_education_updated, specialization_updated, language_skill_updated, driving_license_updated, work_experience_updated, cv_uploaded
  8. CRM: newsletter_sent, newsletter_opened, newsletter_clicked, whatsapp_sent, whatsapp_clicked

Mein Vorschlag: Genau mit diesem Set starten, daraus zuerst ein stündlich aktualisiertes Activity Profile bauen, und erst danach feinere Events wie Scrolltiefe, Impressionen, Recruiting-Outcomes oder Message-Read-State ergänzen.