38b73f5d4d
(1) requirements.lock: 323 Pakete exakt gepinnt auf das heute getestete Set (fastapi==0.141.1, starlette==1.3.1, sqlalchemy==2.0.35, alembic==1.19.1, asyncpg==0.31.0, pydantic==2.13.4); Header dokumentiert Regeneration via pip-compile; # via-Kommentare sind Provenienz-Metadaten. (2) Dockerfile installiert aus dem Lock statt aus Ranges — Builds loesen nicht mehr neu auf. (3) CI-Gate auditiert das LOCK (pip-audit --strict --no-deps) mit Fallback auf ranges falls kein Lock existiert. (4) deploy-guide.md: Dependencies-aendern-Workflow dokumentiert. Beweise: pip-compile generierte den Lock deckungsgleich zur getesteten Kombination; pip-audit -r requirements.lock = No known vulnerabilities; bash -n Syntax OK.
139 lines
7.2 KiB
Markdown
139 lines
7.2 KiB
Markdown
# 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:<SECRETSTORE>@postgres:5432/crm_db
|
|
- Redis: redis://default:<SECRETSTORE>@redis:6379/0
|
|
- SECRET_KEY: <SECRETSTORE> (min. 32 Zeichen, siehe app/config.py Validierung)
|
|
- MAIL_ENCRYPTION_KEY: <SECRETSTORE> (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.
|