LeadScraper als Frappe Custom App statt Standalone-Service #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Kontext
Architektur-Entscheidung: LeadScraper wird nicht als eigenständiger Python-Service per REST-API an Frappe CRM angebunden, sondern als echte Frappe Custom App, die im selben Bench-Container wie CRM/ERPNext läuft und Frappes eigenen Scheduler/Queue-Worker nutzt statt eines externen REST-Clients.
Abhängigkeit: Erfordert eine laufende Frappe-Instanz. Diese wird im neuen Repo
Docker-Stacks/frappe-crm-erpaufgebaut (siehe dortiges Issue "Docker-Stack: Frappe CRM + ERPNext (branch main) aufsetzen"). Umsetzung dieses Issues erst nach erfolgreichem Abschluss des Docker-Stacks.Die bisherige Architektur-Doku in
Projekt.mddieses Repos (Mautic-Nachfolger-Planung mit REST-API-Import) bleibt als Referenz für die fachliche Logik gültig (Website-/Impressum-Scan, Entscheidungsbaum, Tag-Struktur) — nur der technische Umsetzungsweg ändert sich von "externer Service + REST" zu "native Frappe App".Grundprinzip
Die App läuft im selben Bench-Container wie CRM/ERPNext (installiert per
bench get-appaus diesem Repo, dannbench install-app leadscraper). Kein eigener Container, keine REST-API-Anbindung — direkter Zugriff auf Frappes ORM.Geplante Struktur
Kernentscheidungen (aus bisheriger
Projekt.md, fachlich unverändert gültig)crm-App), nicht das ERPNext-CRM-Modul (laut Frappe zur Deprecation vorgesehen).→ Exaktes Feld-Schema von
CRM Leadmuss nach Inbetriebnahme des Docker-Stacks geprüft werden (bench --site crm.local console→frappe.get_meta("CRM Lead").fields), um das bestehende Feld-Mapping ausProjekt.mdzu verifizieren/anzupassen.frappe.db.exists("CRM Lead", {...}).frappe.desk.doctype.tag.tag.add_tag), automatisch angelegt falls nicht vorhanden — getrennte Tags für Suchbegriff und Region-Code.config.jsonmehr, stattdessen Single-DocTypeLead Scraper Settings(Secrets über Frappes verschlüsseltesPassword-Feld statt Klartext-Datei).bench leadscraper run --query "Polsterei" --regions BY(CLI, wie gewohnt) oder später ein Button in der CRM-UI, derfrappe.enqueue(..., queue="long")auslöst und imqueue-long-Worker des Docker-Stacks läuft.hooks.py: scheduler_events) optional für wiederkehrende automatische Läufe — wird erst konkretisiert, wenn ein fester Rhythmus gewünscht ist (aktuell nicht gefordert, bleibt manuell/on-demand).Offene Punkte für die Umsetzungsphase
CRM Lead-Feldschema verifizieren (s.o.)Comment(Timeline) oder als CRM-eigener Notes-DocType angelegt werden (abhängig von dercrm-App-Struktur, nach Installation prüfbar)requirements.txtder App vs. Bench-globale Python-Umgebung (Frappe-Apps installieren ihre Requirements in die gemeinsame Bench-venv — keine Konflikte mitrequestserwartet)Referenz
Wiederverwendbare Kernlogik aus dem alten Mautic-Projekt (
GitLab/wsc_py_leadscraper):search_leads.py,import_leads.py,region_resolver.py,generate_regions.py— Mautic-unabhängig, direkt portierbar.Detailplanung abgeschlossen, gegen das laufende
crm.localverifiziert (Teil 1 ist fertig:Docker-Stacks/frappe-crm-erp, Branchdevelop, Login funktioniert).Das tatsächliche
CRM Lead-Schema wurde direkt ausapps/crm/crm/fcrm/doctype/crm_lead/crm_lead.jsonim laufenden Container gelesen (66 Felder) — einige Annahmen aus der ursprünglichenProjekt.mdtreffen so nicht zu:Korrigiertes Feld-Mapping
organizationmobile_nowebsiteemaillead_namesource(Link aufCRM Lead Source, kein Freitext; Eintrag „Google Business" muss automatisch angelegt werden — existiert noch nicht)custom_address/custom_city/custom_countrycustom_google_maps_url/custom_google_rating(wie geplant)frappe.desk.doctype.tag.tag.add_tag, verifiziert: erstellt den Tag-Master automatisch)FCRM Note-DocType gefunden (reference_doctype/reference_docname, Dynamic Link) — genau der Mechanismus für "Erneut gefunden am TT.MM.JJJJ"Wichtiger neuer Befund: Persistenz
Das
custom-Image aus Teil 1 deklariert nursites/undlogs/als Docker-Volumes (apps/liegt im Image-Layer). Einbench get-applive im laufenden Container wäre nach einer Container-Neuerstellung weg. Die App muss überapps.jsoninfrappe-crm-erpeingetragen und das Image neu gebaut werden.App-Struktur (final)
Umsetzung erfolgt jetzt Schritt für Schritt (wie bei
frappe-crm-erp), beginnend mitbench new-app leadscraperim laufenden Container.Nachtrag zum Feld-Mapping:
first_nameist aufCRM Leadpflicht (reqd: 1) — stand im ursprünglichen Feld-Dump, wurde aber übersehen, da der erste Dump dasreqd-Flag nicht mit ausgegeben hat. Beim ersten Testlauf voncrm_lead_sync.pyflog prompt einMandatoryError.Lösung: Wird aus dem Impressum-Inhaber (falls gefunden, per Vor-/Nachname gesplittet) befüllt, sonst Fallback auf den Firmennamen — damit blockiert eine fehlende Inhaber-Angabe (der Normalfall bei dieser Datenquelle) nie die Lead-Anlage.
crm_lead_sync.pyist fertig und gegen den laufenden Stack end-to-end verifiziert (Neuanlage, Duplikat-Erkennung inkl. FCRM-Note, tote Website, keine Website/E-Mail — alle vier Pfade korrekt, Tags/Source/Custom-Fields stimmen).Korrektur zur CLI-Befehlsbenennung: Ursprünglich im Plan als
bench leadscraper search/import/runvorgesehen — das gibt es so nicht.benchgruppiert Commands aus Apps nicht pro App (frappe/utils/bench_helper.pymischt alle Commands aller Apps in einen einzigen flachen Namespace). Um Kollisionen mit anderen Apps zu vermeiden, heißen die Befehle jetzt App-präfixiert:bench leadscraper-search --query "..." --regions BY [--dry-run] [--output leads.json]bench leadscraper-import --input leads.json --query "..."bench leadscraper-run --query "..." --regions BY(beides in einem Rutsch)tasks.py+commands.pysind fertig und gegen den laufenden Stack end-to-end verifiziert:--help-Registrierung, Dry-Run-Planung, echte Lead-Anlage per CLI inkl. Duplikaterkennung im zweiten Lauf.Womit die fachliche App-Logik (Schritte 1–6 aus dem Plan) vollständig steht. Fehlt noch Schritt 7: die App dauerhaft machen (
apps.jsoninfrappe-crm-erpergänzen, Image neu bauen,install-appauf dem gebauten Image statt nur live im laufenden Container).Schritt 7 (App dauerhaft machen) abgeschlossen.
apps.jsoninfrappe-crm-erpumLeadScraper-Google(Branchmain) ergänzt, Image neu gebaut. Dabei ein reales Problem gefunden und behoben: BuildKit-Secrets (apps.json) fließen nicht in den Layer-Cache-Key ein — der erste Rebuild-Versuch lief komplettCACHEDdurch und produzierte trotz Exit-Code 0 ein Image ohneleadscraper. Fix:build.sherzwingt jetzt bei jedem Aufruf einen frischenCACHE_BUST-Build-Arg (infrappe-crm-erpcommittet).Zusätzlich auf Wunsch ergänzt:
docker-compose.dev-apps.ymlinfrappe-crm-erp(optional, nicht automatisch geladen): bind-mountet den lokalen App-Checkout in die laufenden Container, damit Code-Änderungen ohne 20–40-Min.-Rebuild sichtbar sind. Live getestet (Host-Änderung sofort im Container sichtbar), danach sauber zurückgebaut.apps.json+Image (bzw. den Dev-Mount lokal) — bewusst kein Docker-Volume fürapps/, damit das Image der reproduzierbare Deploy-Artefakt bleibt. App-Daten (Leads, Settings-Werte, Custom-Field-Inhalte) liegen unabhängig davon immer imsites-Volume.docs/install.mdin diesem Repo: vollständige Installationsanleitung inkl. Tabelle "was liegt wo" (Code/Schema/Secrets/Daten), beide Installationswege, CLI-Referenz, Troubleshooting-Sammlung.Verifiziert nach Rebuild:
leadscraperläuft nativ aus dem Image (bench list-apps), CLI-Befehle registriert, Login funktioniert,Lead Scraper Settingsweiterhin korrekt (Daten haben den Rebuild unbeschadet überstanden, da sie imsites-Volume liegen, nicht im Image).Damit ist der komplette Plan aus diesem Issue umgesetzt.