# LeoCRM Deploy Guide > **Version:** 2.0 > **Date:** 2026-08-20 ## Fast Frontend-Only Deploy (~20s) ```bash bash /a0/usr/projects/leocrm/scripts/fast-deploy.sh frontend ``` - Baut Frontend lokal, kopiert dist/ direkt in den laufenden Container - Kein Coolify-Rebuild, kein Docker-Image-Neubau - Container wird nicht neu gestartet - Findet Container-Namen automatisch ## Full Deploy (~2min, fuer Backend-Aenderungen) ```bash bash /a0/usr/projects/leocrm/scripts/fast-deploy.sh full ``` - Triggert Coolify-Rebuild ueber deploy.py - Fuer Python-Code, Requirements, Migrations ## Wann was? - Nur Frontend (TSX, CSS, etc.): `frontend` - Backend (Python, Dockerfile, requirements): `full` - Beides: erst `full`, dann `frontend` (oder nur `full`) ## Git Workflow 1. Aenderungen in /a0/usr/projects/leocrm 2. `git add -A && git commit -m '...' && git push origin main` 3. Dann deploy ## Dependencies aendern (Lockfile) - requirements.txt = gewuenschte Ranges; requirements.lock = exakt getestetes Set - Nach jeder Aenderung an requirements.txt: `pip install pip-tools && pip-compile requirements.txt -o requirements.lock` - Lock-Diff reviewen (welche transitiven Versionen ziehen die neuen Ranges?) - CI-Gate auditiert das LOCK: `pip-audit -r requirements.lock --strict --no-deps` ## Container-Info - Coolify App UUID: xf7smknlger3hvkrsb910tui (neu erstellt 2026-08-06) - Container-Name aendert sich bei jedem Coolify-Deploy (Suffix) - Frontend-Pfad im Container: /app/frontend/dist - Worker: Teil der Docker-Compose-App (crm_worker service) - DB: Teil der Docker-Compose-App (postgres service, pgvector/pgvector:pg16) - Redis: Teil der Docker-Compose-App (redis service, redis:7-alpine) ## Server - Host: 46.225.91.159 - SSH Key: /a0/usr/workdir/.ssh/coolify-01-root ## Zugaenge > ⚠️ **SECURITY (E6):** Keine Credentials im Repo! Alle Werte liegen im Secretstore > (Agent-Zugriff via `§§secret(...)`-Aliase) bzw. in Coolify Environment Variables. > > ⚠️ **ROTATION ERFORDERLICH:** Die folgenden Werte waren bis 2026-08-24 in dieser > Datei eingecheckt und gelten als kompromittiert (Git-Historie). ALLE müssen rotiert > werden — siehe Abschnitt "Credential-Rotation" unten. - Web-UI: https://crm.media-on.de/login (Admin-Credentials: Secretstore) - Forgejo: https://forgejo.media-on.de/Leopoldadmin/leocrm (API-Token: Secretstore ``) - Coolify: https://server.media-on.de (API-Token: Secretstore, siehe scripts/deploy.py) - Produktions-DB: postgresql+asyncpg://crm_user:@postgres:5432/crm_db - Redis: redis://default:@redis:6379/0 - SECRET_KEY: (min. 32 Zeichen, siehe app/config.py Validierung) - MAIL_ENCRYPTION_KEY: (AES-256 Fernet Key fuer Mail-Passwort-Verschluesselung, in Coolify als Environment Variable setzen) ## Coolify Resources - Project UUID: mzu7fvhtad82ujgmbsmyvxzm - Server UUID: lw80w8scs444gwcw084s00s4 - Private Key UUID: rgcsc0048c04csckk8kogk40 ## Production Resource Recommendations Die docker-compose.yaml hat Development-Defaults (PostgreSQL 512m, Redis 128m). Fuer Produktion mit 50+ Usern, 100k+ Entities, Agenten, Search und Knowledge muessen die Limits erhoeht werden. | Service | Development | Production (50+ User) | Begruendung | |---|---|---|---| | **PostgreSQL RAM** | 512m | 1-2GB | pgvector HNSW + FTS + JSONB Snapshots + Outbox + AuditLog | | **PostgreSQL CPU** | 1.0 | 2.0 | Vector Search + FTS + normale CRM-Queries | | **PostgreSQL Disk** | Named Volume | 50-100GB | Embeddings (768 dim x 100k = ~300MB), JSONB Snapshots, Outbox | | **Redis RAM** | 128m | 256-512m | WS Pub/Sub + Caching + Sessions + ARQ + Rate-Limiting | | **Redis CPU** | 0.5 | 1.0 | Pub/Sub + Cache + Queue | | **App (FastAPI) RAM** | Nicht limitiert | 512m-1GB | WebSocket Connections + Async Tasks | | **App CPU** | Nicht limitiert | 1-2 CPUs | API + WS + LLM-Streaming | | **Worker (ARQ) RAM** | Nicht limitiert | 256-512m | Background Jobs (Indexierung, Agent-Runs, Extraction) | | **Worker CPU** | Nicht limitiert | 1-2 CPUs | LLM-Calls + Embedding + Text-Extraction | ### Skalierung bei Bedarf - **Read-Replicas:** Bei hohem Lese-Aufkommen (Search, FTS, Vector) koennen Read-Replicas fuer PostgreSQL eingerichtet werden. Schreib-Last (Outbox, EntityHistory, AuditLog) bleibt auf dem Master. - **Mehr Worker:** Bei hohem Background-Job-Aufkommen koennen zusaetzliche ARQ-Worker-Container gestartet werden. Queue-Prioritaeten verhindern dass wichtige Jobs hinter langen Index-Jobs warten. - **pgvector auslagern:** Bei sehr grossen Datasets (>1M Embeddings) kann pgvector auf einen separaten PostgreSQL-Node ausgelagert werden. - **Redis Cluster:** Bei sehr hohem Cache-/Pub/Sub-Aufkommen kann Redis Cluster eingesetzt werden. ### LLM-Kosten-Management - **Cost-Tracking:** Der zentrale LLM Client (Phase B.1) trackt Kosten pro Call. - **Budget-Limits:** Pro Agent (Phase F) und pro Tenant (Phase I). - **Cost-Dashboard:** Phase I zeigt LLM-Kosten pro Agent/Workflow/User. - **Alerts:** Budget-Alerts bei Ueberschreitung konfigurierbarer Schwellwerte. ## ARQ Worker Cron-Jobs Der crm_worker Service fuehrt folgende Cron-Jobs aus: | Job | Schedule | Beschreibung | |-----|----------|-------------| | `auto_backup_job` | Taeglich 03:00 | Automatisches Backup (ruft scripts/backup.py auf) | | `audit_retention_cleanup` | Taeglich 04:00 | Audit-Logs aelter als 365 Tage archivieren/loeschen | | `cleanup_expired_trash` | Taeglich 05:00 | Soft-deleted Entities aelter als 90 Tage endgueltig loeschen | | `outbox_cleanup` | Stuendlich | Outbox-Eintraege aelter als 30 Tage loeschen | | `cleanup_expired_sessions` | Stuendlich | Abgelaufene Sessions aus Redis loeschen | ## Container-Entrypoints | Datei | Service | Funktion | |------|---------|----------| | `prestart.sh` | crm_app | Alembic-Migrationen -> DB-Role-Passwoerter -> Plugin-Schema-Sync -> Admin-Seed -> uvicorn Start | | `worker.sh` | crm_worker | ARQ Worker Start mit Cron-Jobs | | `healthcheck.sh` | crm_app | HTTP /api/v1/health oder Redis-Ping | ## Credential-Rotation (E6, 2026-08-24) Die folgenden Credentials waren bis 2026-08-24 in dieser Datei eingecheckt und gelten als **kompromittiert** (Git-Historie). Sie MUESSEN rotiert werden: | # | Credential | Wo rotieren | Nach Rotation aktualisieren | |---|-----------|-------------|------------------------------| | 1 | Forgejo API-Token | Forgejo → Settings → Applications → Token löschen + neu erstellen | Secretstore-Alias `RFC_PASSWORD` | | 2 | Coolify API-Token | Coolify → Keys & Tokens → Token löschen + neu erstellen | scripts/deploy.py liest aus Env `COOLIFY_TOKEN` | | 3 | Production DB-Passwort (crm_user) | Coolify → postgres service → Env `POSTGRES_PASSWORD` + prestart.sh Role-Sync | Coolify Env + Secretstore | | 4 | Redis-Passwort | Coolify → redis service → Env `REDIS_PASSWORD` | Coolify Env (crm_app + crm_worker) | | 5 | SECRET_KEY | Coolify → crm_app → Env `SECRET_KEY` (neuer random 32+ Zeichen Wert) | Coolify Env; Achtung: invalidiert bestehende Sessions | | 6 | Admin-Web-UI-Passwort | Web-UI → Settings → Passwort ändern | Secretstore | | 7 | MAIL_ENCRYPTION_KEY | Coolify → crm_app → Env (neuer Fernet-Key); danach Mail-Account-Passwoerter einmal re-speichern | Coolify Env | Rotations-Reihenfolge: 5 (SECRET_KEY) zuletzt, da es alle Sessions invalidiert. Nach jeder Rotation: Deploy triggern und Health-Check verifizieren.