No description
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-02 19:47:42 +00:00
.idea feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
docs fix(apps): remove erpnext_druckformate, fix image tag 2026-08-23 19:37:41 +02:00
.env fix(apps): remove erpnext_druckformate, fix image tag 2026-08-23 19:37:41 +02:00
.gitignore feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
AGENTS.md feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
apps.json fix(apps): remove erpnext_druckformate, fix image tag 2026-08-23 19:37:41 +02:00
build.sh feat(stack): switch to version-16 and add ecommerce_integrations + ALYF German localization apps 2026-08-22 22:25:34 +02:00
CLAUDE.md feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
docker-compose.dev-apps.yml fix(dev-apps): correct bind-mount source path and override.yml usage 2026-07-25 20:13:21 +02:00
docker-compose.override.yml feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
docker-compose.prod.yml feat(stack): add Frappe CRM + ERPNext docker stack (branch develop) 2026-07-25 16:28:01 +02:00
docker-compose.yml fix(config): update Forgejo domain to git.web-seo-consulting.eu 2026-08-22 22:25:34 +02:00
LICENSE chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:33:02 +02:00
Projekt.md fix(apps): remove erpnext_druckformate, fix image tag 2026-08-23 19:37:41 +02:00
README.md chore(license): add AGPL-3.0-or-later license and copyright notice 2026-09-02 21:33:02 +02:00

Frappe CRM + ERPNext – WSC Standard Stack

Selbst gehostete Frappe-Bench (Branch version-16) mit ERPNext und Frappe CRM, als Basis für LeadScraper-Google, ecommerce_integrations und die deutsche ERPNext-Lokalisierung von ALYF (siehe Projekt.md). Enthält außerdem ner-service, einen eigenständigen spaCy-basierten Mini-Dienst zur Inhaber-Erkennung im LeadScraper-Impressum-Scan (Details: docs/install.md, Abschnitt 9c).

Hinweis: .env enthält lokale Platzhalter-Passwörter (change-me-local). Vor einem Live-Deploy durch echte Werte ersetzen. Werte, die je in Git lagen, gelten als kompromittiert → rotieren.


1. Voraussetzungen

  • Docker Engine v23+ mit BuildKit (Pflicht für --secret beim Image-Build) + Docker Compose v2
  • Für den Live-Betrieb zusätzlich: externes Netz traefik_proxy_network, zentrale Stacks docker-autoheal-neustart, docker-ofelia-cronjobs, docker-docker-backup-backups
  • Lokal (Default): keine zusätzlichen Stacks nötig, direkter Port-Zugriff
  • Die Volume-Ordner unter ./volumes/ müssen vor dem ersten Start existieren (siehe Schritt 2)

2. Image bauen

mkdir -p volumes/{sites,db,redis-queue,backups}
./build.sh

build.sh baut das Image frappe-crm-erp:version-16 per Remote-Git-Build-Context aus dem offiziellen frappe/frappe_docker-Repo (images/custom/Containerfile), mit apps.json als BuildKit-Secret. Kein Vendoring von frappe_docker in dieses Repo nötig.

Aktuell in apps.json: erpnext (Branch version-16), crm (Branch main), die eigenen Apps LeadScraper-Google (main) und ecommerce_integrations (shopware6-dach), sowie die drei ALYF-Apps zur deutschen Lokalisierung erpnext_germany/eu_einvoice/ erpnext_pdf-on-submit (alle version-16) — Details und Begründung siehe Projekt.md.

Nicht in apps.json: erpnext_druckformate ist keine installierbare Frappe-App, sondern ein einmalig auszuführendes CLI-Tool (frappe-pf-init). Als apps.json-Eintrag verursacht es einen Crash-Loop (ModuleNotFoundError, ungültiger Python-Package-Name mit Bindestrichen) — siehe Projekt.md, Abschnitt „Deutsche Lokalisierung (ALYF)".

Weitere eigene Apps aufnehmen: Eintrag in apps.json ergänzen (Git-URL + Branch), dann ./build.sh erneut ausführen — CACHE_BUST sorgt automatisch dafür, dass wirklich neu geklont wird (siehe Abschnitt 6).

frappe/erpnext laufen bewusst auf dem fest versionierten Branch version-16 statt develop — reproduzierbar und kompatibel zu den eigenen Apps, die ebenfalls auf v16 laufen. crm hat keine eigenen version-*-Branches; main deklariert frappe>=15.0.0,<17.0.0 und ist damit zu v16 kompatibel.

Dauert ca. 20–40 Minuten — siehe Abschnitt 6 ("Warum dauert der Build so lange?").


3. Stack starten

Wichtig: docker compose immer aus diesem Stack-Verzeichnis starten (${PWD}-Mounts).

Startbefehle-Referenz (alle Szenarien)

Szenario Befehl Compose-Dateien
Lokal, Standard (Default — kein Dev-Mount, direkter Port) docker compose up -d docker-compose.yml + docker-compose.override.yml (automatisch, da kein -f angegeben)
Lokal, mit LeadScraper-Dev-Mount (Codeänderungen an der App sofort sichtbar, kein Rebuild — siehe Abschnitt 7) docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.dev-apps.yml up -d Alle drei explizit — siehe Warnung unten
Live/Produktiv (Traefik statt Port, Autoheal/Backup-Labels aktiv) docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d docker-compose.yml + docker-compose.prod.yml

Achtung — docker-compose.override.yml wird nur automatisch geladen, wenn docker compose up komplett OHNE -f-Flag aufgerufen wird (erste Zeile der Tabelle). Sobald irgendein -f explizit angegeben wird (Dev-Mount- oder Live-Zeile), ersetzt das Docker Composes automatische Dateiauswahl vollständig — override.yml muss dann selbst mit aufgeführt werden, sonst fehlt der lokale Port-Zugriff ersatzlos (Symptom: Start läuft fehlerfrei durch, aber curl localhost:8080 liefert „Connection refused").

docker-compose.override.yml und docker-compose.prod.yml nicht gemeinsam verwenden — Port-Mapping vs. Traefik schließen sich gegenseitig aus.

Nach dem Start prüfen:

docker compose ps
docker compose logs configurator

4. Site anlegen (einmalig, manuell)

docker compose exec backend bench new-site crm.localdomain \
  --mariadb-user-host-login-scope='172.%.%.%' \
  --db-root-password "$DB_PASSWORD" \
  --admin-password <admin-passwort> \
  --install-app erpnext \
  --install-app crm

Danach lokal erreichbar unter http://localhost:${HTTP_PUBLISH_PORT:-8080} (Login: Administrator / das oben gesetzte Admin-Passwort).


5. Integrationen (nur live, via docker-compose.prod.yml)

Autoheal

autoheal=true auf frontend, db, redis-cache, redis-queue (alle mit Healthcheck).

DB-Backup (shyim/docker-backup) – Schedule 5-Feld

Label auf db: type=mysql, BACKUP_SCHEDULE, Retention BACKUP_RETENTION.

Datei-Backup (Ofelia + backup-helper)

Da shyim nur named volumes sichert (sites ist ein Bind-Mount), läuft das Datei-Backup über den idle backup-helper: Ofelia job-exec packt täglich 05:00 ein tar.gz von sites/ (Uploads, site_config.json) nach ${BACKUP_PATH}/frappe-crm-erp/sites/ (Retention laut BACKUP_RETENTION, Default 5 Tage).


6. Warum dauert der Build so lange?

Für version-16 gibt es zwar ein vorgebautes Docker-Hub-Image (layered-Typ), dieser Stack nutzt aber bewusst den custom-Image-Typ (nötig, um die eigenen Apps aus apps.json mit einzubauen) — der komplett aus Source baut:

  1. System-Pakete installieren (Nginx, wkhtmltopdf, Chromium, MariaDB-Client, Node via nvm, Build-Tools wie gcc/build-essential für Python-Pakete wie pandas)
  2. bench init klont Frappe (Branch version-16) sowie alle Apps aus apps.json frisch per Git
  3. Python-Dependencies pro App installieren
  4. Frontend-Assets bauen (Yarn/Vite) — für Frappe, ERPNext und insbesondere die Vue-basierte CRM-App der zeitaufwändigste Schritt

Es gibt keine wiederverwendbaren Docker-Hub-Layer, da diese nur für versionierte Branches existieren.

Wichtig — CACHE_BUST: BuildKit-Secrets (apps.json) fließen bewusst nicht in den Docker-Layer-Cache-Key ein. Änderst du apps.json (neue App, anderer Branch-Stand) OHNE CACHE_BUST zu ändern, verwendet Docker stillschweigend das alte, gecachte Build-Ergebnis weiter — der bench init-Schritt läuft dann gar nicht neu! build.sh setzt deshalb bei jedem Aufruf automatisch --build-arg CACHE_BUST=$(date +%s), damit bench init (Klonen aller Apps aus apps.json) garantiert neu ausgeführt wird. System-Pakete/Node/wkhtmltopdf (die teuersten, aber selten wechselnden Schritte) bleiben davon unberührt und weiterhin gecacht.


7. Custom Apps lokal entwickeln, ohne jedes Mal neu zu bauen

Für aktive Entwicklung an einem eigenen App-Repo (z. B. LeadScraper-Google) ist ein 20–40-minütiger Rebuild pro Codeänderung unpraktikabel. Dafür gibt es das optionale docker-compose.dev-apps.yml: es mountet den lokalen Git-Checkout des Apps direkt in die laufenden Container, Codeänderungen sind sofort sichtbar (nach einem Service-Neustart, kein Rebuild nötig).

Startbefehl: siehe Tabelle in Abschnitt 3 ("Lokal, mit LeadScraper-Dev-Mount") — dort auch der wichtige Hinweis zu docker-compose.override.yml, das dabei explizit mit angegeben werden muss.

Wichtig:

  • Das Overlay ändert nur die laufenden Container, nicht das Image. apps.json + ./build.sh bleiben die einzige maßgebliche, reproduzierbare Quelle für das tatsächlich gebaute (und live deployte) Image.
  • Vor jedem Push/Live-Deploy den echten apps.json+Rebuild-Weg gegentesten — sonst kann der bind-gemountete Stand vom tatsächlich gebauten Image abweichen.
  • App-Daten (angelegte Datensätze, Einstellungen, Custom-Field-Werte) liegen unabhängig vom Overlay immer im sites-Volume — dieses Overlay betrifft ausschließlich App-Code.
  • Neue Apps ergänzen: Block in docker-compose.dev-apps.yml nach dem leadscraper-Muster duplizieren, Pfad-Variable in .env ergänzen.
  • Nach backend-Neustart auch frontend neu starten (siehe Abschnitt 9a in docs/install.md).

8. Nützliche Befehle

docker compose config -q                          # Konfiguration validieren
docker compose up -d
docker compose logs -f backend
docker compose exec backend bench --site crm.localdomain <command>
docker compose down

Lizenz

Copyright (C) 2026 Christian Säum – web-seo-consulting.eu

Dieses Projekt steht unter der GNU Affero General Public License, Version 3 oder (nach deiner Wahl) einer späteren Version (AGPL-3.0-or-later). Der vollständige Lizenztext steht in der Datei LICENSE.

Du darfst die Software nutzen, weitergeben und – auch kommerziell – verkaufen. Gibst du eine veränderte Fassung weiter oder betreibst du sie über ein Netzwerk (z. B. als Dienst), muss deren vollständiger Quellcode ebenfalls unter der AGPL-3.0-or-later verfügbar sein. Der Copyright-Hinweis und die Nennung des ursprünglichen Autors dürfen nicht entfernt werden.

Diese Angabe betrifft nur die in diesem Repository enthaltenen eigenen Dateien (Konfiguration, Skripte, Anpassungen). Eingebundene Fremdsoftware und Container-Images unterliegen weiterhin ihren eigenen Lizenzen.