Ein Anfang für ein Repo für FreeCad Modelle
  • Python 79.7%
  • HTML 12%
  • CSS 4.5%
  • JavaScript 3.5%
  • Dockerfile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Ralf Warmuth acaeafc184
All checks were successful
Test and Build FreeCAD PLM Images / build-image (push) Successful in 6m36s
Document CAD source provenance release in addon 0.1.3
2026-09-12 01:21:33 +02:00
.forgejo/workflows Prune runner cache before FreeCAD build 2026-07-19 02:54:51 +02:00
docker Pin worker to FreeCAD 1.1.1 2026-07-19 02:43:22 +02:00
freecad_plm Link Bambuddy prints to PLM revisions 2026-08-30 21:58:15 +02:00
planning Document CAD source provenance release in addon 0.1.3 2026-09-12 01:21:33 +02:00
plm Support local CAD and print project revision sources 2026-09-03 00:55:31 +02:00
.dockerignore Add upload budget limits and audit docs 2026-07-09 12:33:57 +02:00
.env.example Link Bambuddy prints to PLM revisions 2026-08-30 21:58:15 +02:00
.gitignore Support Django reverse proxy deployment 2026-06-30 22:52:24 +02:00
CHANGELOG.md Release server v0.1.0 2026-07-20 00:11:09 +02:00
docker-compose.image.yml Link Bambuddy prints to PLM revisions 2026-08-30 21:58:15 +02:00
docker-compose.yml Link Bambuddy prints to PLM revisions 2026-08-30 21:58:15 +02:00
Dockerfile Pin worker to FreeCAD 1.1.1 2026-07-19 02:43:22 +02:00
manage.py init 2026-06-26 09:50:46 +02:00
README.md Link Bambuddy prints to PLM revisions 2026-08-30 21:58:15 +02:00
requirements.txt Harden upload limits and XML parsing 2026-07-09 14:14:25 +02:00
VERSION Release server v0.1.0 2026-07-20 00:11:09 +02:00

FreeCAD-PLM

Ein neues Django-basiertes PLM/PDM fuer FreeCAD-Dateien.

Lokal starten

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python manage.py migrate
.venv/bin/python manage.py setup_plm_roles
.venv/bin/python manage.py createsuperuser
.venv/bin/python manage.py runserver

Die PLM-Oberflaeche startet unter http://127.0.0.1:8000/ und nutzt http://127.0.0.1:8000/login/ fuer die normale Anmeldung. Die technische Django-Admin-Oberflaeche liegt weiterhin unter http://127.0.0.1:8000/admin/.

Serverbetrieb Mit Docker Compose

Der empfohlene Serverpfad nutzt Docker Compose mit PostgreSQL, lokalen Datenverzeichnissen und einem separaten Worker. Web und Worker werden aus getrennten Docker-Targets gebaut. Beide enthalten die PLM-Anwendung; nur das Worker-Image enthält FreeCAD/FreeCADCmd.

Der Forgejo-Workflow in .forgejo/workflows/build-image.yml baut bei jedem Push nach main oder master automatisch zwei Images aus dem lokalen Dockerfile, fuehrt die Django-Tests aus und veroeffentlicht nur bei bestandenen Tests. Das Web-Image nutzt das Build-Target web ohne FreeCAD und bleibt dadurch klein; nur das Target worker enthaelt das auf FreeCAD 1.1.1 gepinnte und per SHA-256 gepruefte offizielle AppImage:

git.home.schumbi.de/ralf/freecad-plm-web:latest
git.home.schumbi.de/ralf/freecad-plm-web:<commit-sha>
git.home.schumbi.de/ralf/freecad-plm-worker:latest
git.home.schumbi.de/ralf/freecad-plm-worker:<commit-sha>

Server Mit Fertigem Image Starten

git clone ssh://home.schumbi.de/ralf/freecad-plm.git /opt/freecad-plm
cd /opt/freecad-plm
cp .env.example .env
$EDITOR .env

In .env mindestens setzen:

DJANGO_SECRET_KEY=replace-with-a-long-random-secret
DJANGO_ALLOWED_HOSTS=plm.example.local,localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=https://plm.example.local
PLM_PUBLIC_URL=https://plm.example.local
DJANGO_SECURE_SSL_REDIRECT=0
DJANGO_SECURE_HSTS_SECONDS=0
DJANGO_SESSION_COOKIE_SECURE=1
DJANGO_CSRF_COOKIE_SECURE=1
PLM_LOG_LEVEL=INFO
DJANGO_LOG_LEVEL=INFO
DJANGO_DB_LOG_LEVEL=WARNING
GUNICORN_LOG_LEVEL=info
GUNICORN_ACCESS_LOG=1
POSTGRES_PASSWORD=replace-with-a-strong-database-password
PLM_WEB_IMAGE=git.home.schumbi.de/ralf/freecad-plm-web:latest
PLM_WORKER_IMAGE=git.home.schumbi.de/ralf/freecad-plm-worker:latest
PLM_USER=plm
PLM_UID=1000
PLM_GID=1000
FREECADCMD_COMMAND=freecadcmd
PLM_MAX_FCSTD_UPLOAD_BYTES=200000000
PLM_MAX_CAD_UPLOAD_BYTES=200000000
PLM_MAX_PROJECT_ZIP_BYTES=500000000
PLM_MAX_ZIP_MEMBERS=2000
PLM_MAX_ZIP_UNCOMPRESSED_BYTES=2147483648
PLM_MAX_ZIP_MEMBER_BYTES=200000000
BAMBUDDY_URL=http://bambuddy.example.local:8000
BAMBUDDY_API_KEY=bb_...
BAMBUDDY_TIMEOUT_SECONDS=10
BAMBUDDY_SOURCE_SYNC_ENABLED=0
BAMBUDDY_SOURCE_SYNC_PRINTER_IDS=

Das Runtime-Image enthaelt den User plm mit UID/GID 1000:1000. PLM_USER sollte deshalb auf plm bleiben. PLM_UID und PLM_GID dokumentieren, wem die lokalen Verzeichnisse auf dem Host gehoeren sollen; die Werte zeigt id oder id <user>.

Die PLM_MAX_*-Werte begrenzen FCStd-, STEP-/STL-, Projekt-ZIP- und 3MF-Uploads gegen sehr große Dateien und ZIP-Bomben. Die Defaults sind für ein LAN-Team konservativ und können bei Bedarf höher gesetzt werden.

Für lesende Bambuddy-Abfragen genügt ein eigener API-Key mit Read Status. Der automatische Source-3MF- und Revisionslink-Sync benötigt zusätzlich Manage Archives sowie eine explizite Drucker-ID, beispielsweise BAMBUDDY_SOURCE_SYNC_PRINTER_IDS=1. Der Key bleibt in der Laufzeitumgebung und wird weder in der Datenbank noch im Browser ausgegeben. PLM_PUBLIC_URL ist die von Bambuddy aus erreichbare Browser-Basisadresse des PLM. Der Worker setzt daraus bei laufenden und abgeschlossenen Drucken einen Link direkt auf die eindeutig erkannte Revision; bereits vorhandene externe Links werden nicht überschrieben. BAMBUDDY_TIMEOUT_SECONDS darf zwischen 1 und 60 Sekunden liegen. Unter Verwaltung -> Integrationen zeigt der Verbindungstest auch, ob der Key den Source-Upload ausführen darf.

Der Compose-Worker laeuft zusaetzlich mit cap_drop: ALL, no-new-privileges, read-only Root-FS, tmpfs fuer /tmp und /var/tmp sowie einfachen CPU-/RAM-/PID-Grenzen.

Lokale Verzeichnisse fuer Modelle/Uploads und statische Dateien anlegen:

mkdir -p storage staticfiles
sudo chown -R 1000:1000 storage staticfiles

Start:

docker compose -f docker-compose.image.yml pull
docker compose -f docker-compose.image.yml up -d

storage/ liegt neben der Compose-Datei und enthaelt hochgeladene Modelle, Revisionen und erzeugte Artefakte. staticfiles/ enthaelt nur neu generierbare Django-Static-Dateien.

Die verbindliche Reihenfolge fuer Update, Zustandspruefung, konsistentes Backup und Restore-Test steht in planning/PRODUCTION_CHECKLIST.md.

Nach dem ersten Start:

docker compose -f docker-compose.image.yml exec web python manage.py setup_plm_roles
docker compose -f docker-compose.image.yml exec web python manage.py createsuperuser

Betrieb Hinter Nginx

Wenn Django hinter einem Reverse Proxy per HTTPS erreichbar ist, muessen die oeffentlichen Hosts und Origins in .env stehen:

DJANGO_ALLOWED_HOSTS=jellyfin.schumbi.de,localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=https://jellyfin.schumbi.de
PLM_HTTP_PORT=8000

Eine einfache nginx-Site fuer den lokalen Compose-Port:

server {
    listen 443 ssl http2;
    server_name jellyfin.schumbi.de;

    ssl_certificate /etc/letsencrypt/live/jellyfin.schumbi.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/jellyfin.schumbi.de/privkey.pem;

    client_max_body_size 512m;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
    }
}

Nach Aenderungen an .env den Web-Container neu erstellen:

docker compose -f docker-compose.image.yml up -d --force-recreate web worker

Debugging Und Logs

Web- und Worker-Logs landen auf stdout/stderr und sind direkt ueber Docker Compose abrufbar:

cd /opt/freecad-plm
docker compose -f docker-compose.image.yml logs -f --tail=200 web
docker compose -f docker-compose.image.yml logs -f --tail=200 worker
docker compose -f docker-compose.image.yml logs -f --tail=300 web worker

Fuer die lokale Testing-Instanz entsprechend:

cd ~/freecad-plm-testing
docker compose -f docker-compose.image.yml logs -f --tail=300 web worker

Die Ausfuehrlichkeit laesst sich in .env steuern:

PLM_LOG_LEVEL=DEBUG
DJANGO_LOG_LEVEL=DEBUG
DJANGO_DB_LOG_LEVEL=WARNING
GUNICORN_LOG_LEVEL=debug
GUNICORN_ACCESS_LOG=1
  • PLM_LOG_LEVEL: App-Logger fuer plm.* und Root-Logger.
  • DJANGO_LOG_LEVEL: Django-Logger inklusive Request-/Exception-Logging.
  • DJANGO_DB_LOG_LEVEL: SQL-Logging ueber django.db.backends; DEBUG ist sehr laut und nur fuer gezielte Datenbankdiagnose gedacht.
  • GUNICORN_LOG_LEVEL: Gunicorn-Loglevel.
  • GUNICORN_ACCESS_LOG: 1 schreibt HTTP-Access-Logs nach stdout, 0 deaktiviert sie.

Nach Aenderungen an diesen Werten:

docker compose -f docker-compose.image.yml up -d --force-recreate web worker

DJANGO_DEBUG=1 kann in einer lokalen Testumgebung zusaetzlich helfen, sollte aber nicht fuer oeffentlich erreichbare Instanzen gesetzt werden.

Image Manuell Bauen

Normalerweise baut der Forgejo-Workflow in diesem Repo die Images. Manuell geht es so (Web ohne FreeCAD, Worker mit FreeCAD):

git clone ssh://home.schumbi.de/ralf/freecad-plm.git /opt/freecad-plm-build
cd /opt/freecad-plm-build
docker build --target web -t git.home.schumbi.de/ralf/freecad-plm-web:latest .
docker build --target worker -t git.home.schumbi.de/ralf/freecad-plm-worker:latest .
docker push git.home.schumbi.de/ralf/freecad-plm-web:latest
docker push git.home.schumbi.de/ralf/freecad-plm-worker:latest

Image-Build Ausloesen

Im Normalfall reicht ein Push ins App-Repo:

cd /home/ralf/devel/freecad-plm/freecad-plm
git push

Der Forgejo-Workflow Test and Build FreeCAD PLM Images startet bei Push nach main oder master automatisch. Er baut Web- und Worker-Image, fuehrt die Tests aus und pusht nur bei gruenen Tests. Den Lauf findest du in Forgejo unter:

ralf/freecad-plm -> Actions -> Test and Build FreeCAD PLM Images

Wenn ein Build ohne neuen Commit erneut laufen soll, kann der Workflow dort auch manuell ueber Run workflow gestartet werden. Nach einem erfolgreichen Lauf sind die Registry-Images aktualisiert:

git.home.schumbi.de/ralf/freecad-plm-web:latest
git.home.schumbi.de/ralf/freecad-plm-web:<commit-sha>
git.home.schumbi.de/ralf/freecad-plm-worker:latest
git.home.schumbi.de/ralf/freecad-plm-worker:<commit-sha>

Updates

Wenn das Image neu gebaut wurde:

cd /opt/freecad-plm
git pull
docker compose -f docker-compose.image.yml pull
docker compose -f docker-compose.image.yml up -d

Lokaler Compose-Build

Alternativ kann das App-Repo lokal ein Image bauen. Das ist fuer Entwicklung praktisch, auf dem Server aber langsamer als das fertige Registry-Image:

docker compose up -d --build

Rollen

Die V1-Rollen werden als Django-Gruppen angelegt:

.venv/bin/python manage.py setup_plm_roles
  • reader: ansehen und herunterladen
  • editor: ansehen, herunterladen und Revisionen hochladen
  • admin: volle PLM-Verwaltung

PLM-Admins koennen Benutzer und Addon-Tokens in der normalen Weboberflaeche unter Verwaltung pflegen. Die normale Anmeldung fuehrt direkt in das PLM-WebUI. Der Django-Admin unter /admin/ bleibt als technische Fallback-Verwaltung erhalten und ist von der Login-Seite aus verlinkt.

Die Web-Verwaltung kann:

  • Benutzer anlegen, aktivieren/deaktivieren und Rollen setzen.
  • Passwoerter fuer Benutzer neu setzen.
  • API-Tokens fuer Benutzer anlegen, bearbeiten und widerrufen.

Token-Rechte werden ueber Presets vergeben:

  • Nur Lesen: read
  • Addon Standard: read, write, checkout
  • Admin/Vollzugriff: read, write, checkout, admin

Admin/Vollzugriff kann nur fuer Benutzer mit PLM-Admin-Rolle oder Superuser vergeben werden. Der Klartext eines API-Tokens wird nur direkt nach dem Anlegen angezeigt; danach bleibt nur der Prefix sichtbar.

Kurzworkflow

  1. Projekt als admin/Superuser in der PLM-Oberflaeche anlegen oder vorhandenes Projekt oeffnen.
  2. Teil oder Baugruppe im Projekt mit initialer .FCStd-, .step-, .stp- oder .stl-Datei anlegen.
  3. Bei FCStd die FreeCAD-Metadaten prüfen. Teilenummer und Name können leer bleiben; dann nutzt das PLM FreeCAD-Id/Label. Bei STEP/STL wird der Dateiname als Name verwendet. Fehlt eine Nummer, vergibt das PLM automatisch P-001, P-002, ...
  4. Neue Revisionen werden automatisch kanonisch als R0001, R0002, ... vergeben; alte oder testweise abweichende Codes werden bei der naechsten Nummer ignoriert.
  5. Beim Hochladen einer neuen Revision fehlende oder abweichende FreeCAD-Property PLMRevision verwerfen oder als PLM-normalisierte Kopie speichern.
  6. Optional Anmerkungen ergaenzen.
  7. Optional Revision freigeben (nur admin/Superuser).
  8. Aeltere freigegebene Revision als obsolet markieren (nur admin/Superuser), wenn eine neuere Revision gueltig ist.
  9. Globale Suche in der Topbar nutzen: Projekte, Teile, Revisionen und Dateipfade finden (/search/?q=...).

Suche

Die globale Suche in der Topbar durchsucht Projekte, Teile, Revisionen und Dateipfade in Projektständen. Auf der Ergebnisseite kann zusätzlich nach Projekt, Revisionsstatus, CAD-Format und Teilekategorie gefiltert werden; die Facetten funktionieren auch ohne Suchtext. Auf Listen-Seiten gibt es weiterhin einen lokalen Filter in der jeweiligen Toolbar.

Die Teilseite verbindet Revisionen, Freigaben, synchronisierte 3MF-Slicer-Stände, Fertigungsdateien und Fertigungsläufe in einem gemeinsamen Lebenszyklus. Baugruppen zeigen außerdem einen aufklappbaren Referenzbaum aus dem historischen Projektstand. CAD-Revisionen und Fertigungsdateien können per Drag-and-drop hochgeladen werden. Im 3D-Viewer lassen sich PLM-Anmerkungen an einem Modellpunkt verankern.

Projektstaende

Projekte mit .FCStd-, .step-, .stp- und .stl-Dateien können als ZIP importiert werden. Das PLM legt einen Projektstand an und speichert, welche Revisionen unter welchen relativen Pfaden zusammengehören. Der Projektstand kann wieder als ZIP heruntergeladen werden.

STEP und STL können entweder primäre, unveränderliche CAD-Revisionen sein oder als von einer FCStd-Revision abgeleitete Artefakte vorliegen. Primäre STL-Dateien werden direkt im Web-Viewer angezeigt. Primäre STEP-Dateien laufen für Vorschau und Analyse durch den FreeCADCmd-Worker. Nur FCStd-Revisionen können ausgecheckt und bearbeitet werden; STEP/STL in einem FCStd-Projektstand bleiben schreibgeschützte Begleitdateien.

Wird später eine FCStd-Revision zu einem bisher als STEP/STL geführten Teil hochgeladen, kann im Uploadformular optional ein Projektstand ausgewählt werden. Das PLM erzeugt dann einen neuen Stand, ersetzt darin den bisherigen STEP/STL-Pfad durch den FCStd-Pfad und lässt den gewählten Ausgangsstand unverändert. Ohne Auswahl wird nur die neue Revision angelegt.

Der normale Download einer Revision liefert eine einzelne .FCStd nur dann, wenn sie keine FreeCAD-Referenzen enthaelt. Hat eine Datei Referenzen, liefert der Download automatisch ein ZIP mit der Datei und ihren rekursiv referenzierten Dateien aus demselben Projektstand.

Projektstand, Planung und V1-Abnahme-Checkliste stehen in planning/; fuer die manuelle V1-Abnahme siehe planning/V1_ACCEPTANCE.md.

FreeCAD-Addon-API

Das PLM stellt JSON-Endpunkte unter /api/ bereit. Sie sind fuer ein vanilla-FreeCAD-Addon gedacht und unterstuetzen Bearer Tokens:

.venv/bin/python manage.py create_api_token addon-user "FreeCAD Addon" --scope read --scope write --scope checkout

Der ausgegebene Token wird nur einmal angezeigt und danach als Header gesendet:

Authorization: Bearer plm_pat_...

Token-Scopes:

  • read: Projekte, Teile, Revisionen und Dateien lesen

  • write: Teile bearbeiten/anlegen und Anmerkungen schreiben

  • checkout: Checkout, Check-in und Cancel

  • admin: Projektanlage/-bearbeitung ueber API

  • GET/POST /api/projects/

  • POST /api/projects/import/

  • GET/POST /api/projects/<id>/

  • POST /api/projects/<id>/snapshots/import/

  • GET/POST /api/projects/<id>/parts/

  • POST /api/projects/<id>/parts/create-fcstd/

  • GET/POST /api/parts/<id>/

  • GET /api/revisions/<id>/

  • POST /api/revisions/<id>/notes/

  • GET /api/revisions/<id>/file/

  • GET /api/revisions/<id>/manifest/

  • GET/POST /api/revisions/<id>/slicer-project/

  • GET /api/manufacturing-files/<id>/file/

  • POST /api/revisions/<id>/checkout/

  • GET /api/checkouts/active/

  • GET /api/checkouts/<id>/manifest/

  • POST /api/checkouts/<id>/files/add/

  • POST /api/checkouts/<id>/files/remove/

  • POST /api/checkouts/<id>/checkin/

  • POST /api/checkouts/<id>/cancel/

  • GET/POST /api/parts/<id>/annotations/

  • POST/DELETE /api/annotations/<id>/

Projektbearbeitung ueber POST /api/projects/<id>/ braucht Scope admin und akzeptiert dieselben Stammdaten wie das WebUI: code, name, status, project_date, description und is_archived.

Lokale FreeCAD-Dateisets koennen als Projektstand importiert werden. Das Addon sendet dafür ein ZIP mit relativen .FCStd-, .step-, .stp- und .stl-Pfaden an POST /api/projects/<id>/snapshots/import/ mit Scope write. Fuer den Kombiflow "Projekt anlegen und ZIP importieren" nutzt es POST /api/projects/import/ mit Scope admin.

Für Neues Teil nutzt das Addon POST /api/projects/<id>/parts/create-fcstd/ mit den Scopes write und checkout. Das Addon erzeugt die leere FCStd-Datei intern; eine vorher lokal gespeicherte Benutzerdatei ist nicht erforderlich. Der Server legt Teil und Revision R0001 gemeinsam an. Mit checkout_id wird die neue Datei direkt in den lokal geöffneten Projekt-Checkout aufgenommen. Ohne checkout_id entsteht ein eigener Checkout für das neue Teil. Schlägt die serverseitige Teilanlage oder Aufnahme in den Checkout fehl, werden Teil, Revision und Audit-Einträge nicht als unvollständiger Datenbankstand gespeichert.

Mit GET/POST /api/revisions/<id>/slicer-project/ verwaltet das Addon genau einen bearbeitbaren 3MF-Slicer-Arbeitsstand je CAD-Revision. Ein Update sendet den zuletzt gelesenen Server-Hash als base_sha256; ein veralteter Stand wird mit HTTP 409 abgelehnt und niemals still überschrieben. Normale hochgeladene Slicer-/Fertigungsdateien bleiben davon getrennt und unveränderlich. Der Arbeitsstand wird im WebUI als Slicer-Projekt (Arbeitsstand) angezeigt.

Checkout ist exklusiv pro Teil/Baugruppe. Das Checkout-Manifest enthaelt Root-Datei, referenzierte Revisionen, relative Pfade, Hashes und Download-URLs. Der Check-in erzeugt nur fuer modellrelevante FCStd-Aenderungen neue unveraenderliche Revisionen; reine FreeCAD-Speicherartefakte wie GuiDocument.xml, ShapeAppearance*, LastModified*, PLMRevision, lokale Checkout-Pfade in BOM-/XML-Attributen und winziges Placement-Floating-Point-Rauschen werden durch die technische Signatur ignoriert.

FreeCADCmd

Exportjobs werden mit FREECADCMD_COMMAND ausgefuehrt. Das Docker-Worker-Image enthaelt FreeCAD 1.1.1 aus dem offiziellen x86_64-AppImage; Version und SHA-256 sind im Dockerfile fest gepinnt. Ohne eigene Einstellung versucht das PLM zuerst FreeCADCmd und faellt auf lokalen Installationen auf Flatpak org.freecad.FreeCAD mit --command=FreeCADCmd und /tmp-Freigabe zurueck, wenn Flatpak vorhanden ist.

Beispiel fuer eine explizite Flatpak-Konfiguration:

FREECADCMD_COMMAND='flatpak run --filesystem=/tmp --branch=stable --arch=x86_64 --command=FreeCADCmd org.freecad.FreeCAD' .venv/bin/python manage.py process_export_jobs

PNG-Ansichten werden ohne FreeCAD-GUI erzeugt. Der Worker exportiert die Revision mit FreeCADCmd zuerst als STEP-Artefakt und als temporaeres STL-Vorschau-Mesh. Danach rendert das PLM aus dem STL-Mesh feste PNG-Ansichten. Dafuer wird kein FreeCAD-Fenster, kein Qt-Viewport und kein xvfb-run benoetigt.

Empfohlene Server-Konfiguration:

FREECADCMD_COMMAND='freecadcmd'
PREVIEW_PNG_WIDTH=400
PREVIEW_PNG_HEIGHT=300
PROCESS_EXPORT_JOBS_INLINE=0

Mit PROCESS_EXPORT_JOBS_INLINE=0 legt die Weboberflaeche Export- und PNG-Jobs nur an. Der Docker-Worker verarbeitet sie im Hintergrund. So muss der Webprozess kein FreeCAD starten.

Auf einem Server mit nativer FreeCAD-Installation reicht meistens:

FREECADCMD_COMMAND=/usr/bin/FreeCADCmd .venv/bin/python manage.py process_export_jobs