28 KiB
🤖 JARVIS - Übergabe Dokumentation
Projekt: JARVIS KI-Assistent + Business Automation Erstes Deployment: 12.09.2026 Status: ✅ Live auf VPS 72.61.186.98 (Postgres, Redis, Ollama, n8n, JARVIS-API, JARVIS-Web) Owner: Jonny (MBO-Tech-IT)
📋 Übersicht
JARVIS ist ein vollständig selbst gehosteter AI-Assistant + Business Automation Stack auf einem VPS mit Docker-Orchestrierung. Chat-Zugriff läuft über eine eigene Web-Oberfläche (React) und spricht über Claude Tool Use direkt mit Kalender und E-Mail-Postfach.
Kernkomponenten:
- 🤖 KI-Backend: Claude API (Chat + Tool Use) + Ollama (lokale Embeddings)
- 💾 Datenbank: PostgreSQL mit
pgvector-Extension (strukturierte Daten + Vector Search in einer DB, kein separates Milvus) - ⚡ Cache: Redis (aktuell nur fürs Health-Check vorbereitet, noch nicht aktiv genutzt)
- 🔄 Automation: n8n (Workflow Engine) - Wetter- und E-Mail-Cache laufen bereits darüber
- 📡 API: FastAPI (Python Backend,
main.py) - 🌐 Web-Frontend: React/Vite, nginx-served
- 🔌 Externe Integrationen: Nextcloud-Kalender (CalDAV), E-Mail-Postfach (IMAP/SMTP)
- 🌐 Reverse Proxy: bereits vorhandener, JARVIS-fremder Traefik auf dem VPS (siehe unten)
- 🐳 Container: 6 Docker-Container (siehe "Docker Container Status")
🔑 Zugriffsdaten
VPS IP: 72.61.186.98
User: jarvis-core
SSH Key: ~/.ssh/jarvis_core_key
Domain: jarvis.mbo-tech-it.de
Location: /home/jarvis-core/jarvis
SSH-Zugriff
ssh -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key jarvis-core@72.61.186.98
Die Flags -F /dev/null -o IdentitiesOnly=yes sind nötig, damit die globale
lokale ~/.ssh/config nicht in die Schlüsselauswahl reinpfuscht.
Wichtig: jarvis-core muss in /etc/ssh/sshd_config unter AllowUsers stehen, sonst wird jeder Key mit "Permission denied" abgelehnt, obwohl der Key korrekt ist (passiert am 12.09.2026, gefixt durch Ergaenzen von jarvis-core in der AllowUsers-Zeile + systemctl reload ssh).
n8n-Zugriff
URL: https://n8n.jarvis.mbo-tech-it.de
User: jonny@mbo-tech-it.de (Owner-Account, Passwort nicht in dieser Doku)
API-Keys fuer die n8n-REST-API werden unter Settings -> n8n API verwaltet (pro Key eigenes Ablaufdatum). Aktuell existieren: "JARVIS Weather Workflow" (Ablauf 12.10.2026) und "JARVIS Email Workflow Runtime" (Ablauf 13.10.2026, fuer den E-Mail-Cache-Workflow angelegt). Die Key-Werte selbst sind nirgends dauerhaft gespeichert (nur beim Erstellen einmalig sichtbar) - bei Bedarf einfach einen neuen erstellen.
Database Credentials
PostgreSQL User: jarvis
PostgreSQL Database: jarvis (n8n hat eine eigene DB "n8n" in derselben Instanz)
PostgreSQL Port: 5432
Password: in .env (DB_PASSWORD)
Externe Dienste (Zugangsdaten in .env auf dem VPS)
- Nextcloud-Kalender (
NEXTCLOUD_CALDAV_URL,NEXTCLOUD_USER,NEXTCLOUD_APP_PASSWORD):https://cloud.ffw-onza.de/.../ffw-onza-alle/, App-Passwort-Auth - E-Mail-Postfach (
EMAIL_USER,EMAIL_PASSWORD,EMAIL_IMAP_HOST/PORT,EMAIL_SMTP_HOST/PORT):kontakt@mbo-tech-it.deaufmx2f35.netcup.net(IMAP 143 STARTTLS, SMTP 465 implizites TLS) - Claude API (
CLAUDE_API_KEY): console.anthropic.com, separat vom Claude-Pro-Abo
📍 Services & Ports
| Service | URL | Port | Status | Notes |
|---|---|---|---|---|
| Web-Frontend | https://jarvis.mbo-tech-it.de | 80 (intern, nginx) | 🟢 Live | Chat + Dashboard, Shared-Secret-Login mit API_KEY_ADMIN |
| API | https://api.jarvis.mbo-tech-it.de | 8000 (intern) | 🟢 Live | FastAPI Swagger UI: /docs. Alle /api/v1/* Routen ausser /health brauchen Header X-Admin-Key |
| n8n | https://n8n.jarvis.mbo-tech-it.de | 5678 (intern) | 🟢 Live | Workflow Automation - 2 aktive Workflows (Wetter, E-Mail-Cache) |
| Traefik | - | 80/443 | 🟢 Genutzt (fremd) | Server hat bereits einen eigenen Traefik fuer andere Projekte. JARVIS-eigener Traefik-Service wurde entfernt (Port-Konflikt), stattdessen haengt JARVIS per Labels + externem Netzwerk proxy-network am bestehenden Traefik. TLS ueber Let's-Encrypt-Resolver netcup (DNS-01) |
| PostgreSQL | localhost | 5432 | 🟢 Live | Hauptdatenbank + Vector Search, Image pgvector/pgvector:pg16 |
| Redis | localhost | 6379 | 🟢 Live | Läuft und wird im Health-Check geprüft, im Code aber noch nicht aktiv fürs Caching genutzt |
| Ollama | http://72.61.186.98:11434 | 11434 | 🟢 Live | Local LLM Runtime, genutzt für Embeddings (nomic-embed-text gepullt) |
| Milvus | - | - | ⛔ Nie deployt | Ersetzt durch pgvector direkt in Postgres (siehe Phase 3a). Platzhalter-Services milvus/etcd stehen noch in docker-compose.yml, laufen aber nicht |
Traefik-Integration (12.09.2026): JARVIS ist am bestehenden VPS-weiten Traefik
(docker-compose.yml Projekt traefik, /data/docker/compose/traefik/) angehaengt:
externes Docker-Netzwerk proxy-network, Labels an jarvis-api, jarvis-web und n8n
(traefik.docker.network=proxy-network, entrypoints=websecure,
tls.certresolver=netcup). DNS (jarvis A-Record + *.jarvis Wildcard) liegt
bei Netcup. Falls eine neue Subdomain (z.B. foo.jarvis.mbo-tech-it.de) mal
nicht auflöst, obwohl der Wildcard existiert: pruefen, ob ein expliziter
(auch leerer) Eintrag exakt fuer diesen Namen existiert - der blockiert laut
DNS-Wildcard-Regeln (RFC 1034) die Wildcard-Aufloesung nur fuer diesen einen
Namen. Beobachtet (12.09.2026): Auch ohne sichtbaren blockierenden
Eintrag im Netcup-Panel kann die Aufloesung eines frisch fuer eine
DNS-01-Challenge verwendeten Namens (z.B. api.jarvis...) deutlich laenger
brauchen als ein unberuehrter Wildcard-Name (bis zu ~20 Minuten beobachtet,
vermutlich Netcup-interner Nebeneffekt der ACME-TXT-Record-Erstellung) -
einfach abwarten, es loest sich von selbst.
🏗️ Architektur
┌───────────────────────────────────────────────────────────┐
│ Bestehender, JARVIS-fremder Traefik │
│ (VPS-weit, andere Projekte inklusive) │
└───────────────────────────────────────────────────────────┘
│ proxy-network (Labels)
┌───────────┼──────────────┬──────────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌───────────┐
│jarvis-web│ │jarvis-api│ │ n8n │
│(nginx) │ │(FastAPI) │ │ :5678 │
└─────────┘ └────┬─────┘ └─────┬─────┘
│ jarvis-net (intern) │
┌───────────┼───────────┐ │
▼ ▼ ▼ │
┌───────────┐ ┌───────┐ ┌────────┐ │
│ Postgres │ │ Redis │ │ Ollama │ │
│ +pgvector │ │ :6379 │ │ :11434 │ │
│ :5432 │ └───────┘ └────────┘ │
└─────┬─────┘ │
└─── n8n schreibt Cache-Tabellen ─────┘
(weather_cache, email_cache)
Externe Integrationen (kein eigener Container, direkter API-Zugriff aus jarvis-api):
- Nextcloud CalDAV (Kalender lesen/schreiben)
- IMAP/SMTP-Postfach kontakt@mbo-tech-it.de (E-Mails lesen/senden)
- Claude API (Chat + Tool Use)
🐳 Docker Container Status
cd /home/jarvis-core/jarvis
docker compose ps
# Erwartete Ausgabe (6 Container):
# jarvis-postgres Up (healthy)
# jarvis-redis Up (healthy)
# jarvis-ollama Up
# jarvis-n8n Up
# jarvis-api Up
# jarvis-web Up
milvus/etcd stehen zwar noch als Service-Definitionen in
docker-compose.yml (Platzhalter, nie funktionsfähig konfiguriert), werden
aber mit docker compose up -d normalerweise nicht mit hochgezogen, wenn man
gezielt einzelne Services neu startet (docker compose up -d jarvis-api etc.,
so wie es in diesem Projekt durchgängig gemacht wird statt einem globalen
up -d).
📁 Projektstruktur
/home/jarvis-core/jarvis/
├── docker-compose.yml # Container-Orchestrierung (Docker Compose v2 - "docker compose", kein Bindestrich)
├── .env # Umgebungsvariablen (GEHEIM!)
├── init-db.sql # PostgreSQL Basis-Initialisierung (users/conversations/messages/tasks/documents/audit_logs)
├── migrations/ # Nachträgliche Schema-Änderungen, manuell per psql angewendet
│ ├── 002_document_chunks.sql
│ ├── 003_drop_low_data_ivfflat_index.sql
│ ├── 004_weather_cache.sql
│ └── 005_email_cache.sql
├── api/
│ ├── main.py # FastAPI Hauptanwendung (einzige Backend-Datei)
│ └── requirements.txt # Python Dependencies
├── web/ # React/Vite Frontend-Quellcode + Dockerfile + nginx.conf
├── config/ # (ungenutzt)
├── data/ # (ungenutzt - Postgres/Redis/n8n/Ollama persistieren tatsächlich über benannte Docker-Volumes, siehe docker-compose.yml `volumes:`)
└── logs/ # (ungenutzt, kein Service schreibt aktuell hierhin)
Lokal (Entwicklung, dieses Repo): Backend-Code liegt unter Claude outputs/,
Frontend unter web/. Kein dediziertes Git-Repo für dieses Projekt - Dateien
werden per scp direkt auf den VPS deployt.
🔧 Wichtige Befehle
Hinweis: Die installierte Docker-Compose-Version ist v2 (Plugin-Syntax
docker compose, ohne Bindestrich) - das alte docker-compose (mit
Bindestrich) ist auf dem VPS nicht garantiert vorhanden.
Container Management
cd /home/jarvis-core/jarvis
# Alle starten
docker compose up -d
# Alle stoppen
docker compose down
# Logs anschauen
docker compose logs -f
# Spezifischen Service neustarten (Backend-Codeänderung reicht ein restart,
# da main.py per Volume gemountet ist und uvicorn mit --reload läuft)
docker compose restart jarvis-api
# Frontend-Änderung braucht einen echten Rebuild (Multi-Stage-Dockerfile)
docker compose build jarvis-web && docker compose up -d jarvis-web
# In Container gehen
docker compose exec jarvis-api bash
docker compose exec postgres bash
Database Management
# PostgreSQL CLI öffnen
docker exec -it jarvis-postgres psql -U jarvis -d jarvis
# Query ausführen
docker exec jarvis-postgres psql -U jarvis -d jarvis -c "SELECT * FROM users;"
# Migration anwenden (nach scp der .sql-Datei nach migrations/)
docker exec -i jarvis-postgres psql -U jarvis -d jarvis < migrations/00X_name.sql
# Backup erstellen
docker exec jarvis-postgres pg_dump -U jarvis jarvis > jarvis_backup.sql
# Backup wiederherstellen
docker exec -i jarvis-postgres psql -U jarvis jarvis < jarvis_backup.sql
API Testing
# Health Check (kein Header noetig)
curl http://localhost:8000/health
# Admin Stats (Header noetig)
curl -H "X-Admin-Key: $API_KEY_ADMIN" http://localhost:8000/api/v1/admin/stats
# Swagger UI im Browser
https://api.jarvis.mbo-tech-it.de/docs
Backend-Tests lokal ausführen (vor jedem Deploy)
Lokales Python (3.14) kann psycopg2-binary nicht bauen (kein Wheel) - Tests
laufen deshalb in einem python:3.11-slim-Container per SSH:
scp -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key \
"Claude outputs/main.py" "Claude outputs/requirements.txt" \
"Claude outputs/requirements-dev.txt" "Claude outputs/pytest.ini" \
jarvis-core@72.61.186.98:/tmp/jarvis-test/
scp -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key \
"Claude outputs/tests/"*.py jarvis-core@72.61.186.98:/tmp/jarvis-test/tests/
ssh -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key jarvis-core@72.61.186.98 \
"docker run --rm -v /tmp/jarvis-test:/app -w /app python:3.11-slim bash -c \
'pip install -q -r requirements-dev.txt -r requirements.txt && python -m pytest tests/ -v'"
⚙️ Konfiguration (.env, auf dem VPS unter /home/jarvis-core/jarvis/.env)
# Domain
DOMAIN=jarvis.mbo-tech-it.de
# Database
DB_PASSWORD=<generiert>
# Claude / Ollama
CLAUDE_API_KEY=<gesetzt>
CLAUDE_MODEL=claude-sonnet-5 # (Default in main.py, muss nicht in .env stehen)
OLLAMA_EMBED_MODEL=nomic-embed-text # (Default in main.py)
# Admin-Zugriff (Shared Secret fürs Frontend UND alle /api/v1/* Routen)
API_KEY_ADMIN=<generiert>
# Nextcloud-Kalender
NEXTCLOUD_APP_PASSWORD=<gesetzt>
# E-Mail-Postfach kontakt@mbo-tech-it.de
EMAIL_PASSWORD=<gesetzt>
LOG_LEVEL=info
⚠️ WICHTIG: .env enthält Secrets - nicht in Git committen (für dieses
Projekt ohnehin kein Git-Repo im Einsatz)!
🔌 Datenbankschema
PostgreSQL Tables (Datenbank jarvis)
users (init-db.sql)
- Felder: id, username, email, password_hash, api_key, role, is_active
- Es gibt kein echtes Login-System pro Nutzer (siehe "Security" unten) - die
einzige vorhandene Zeile ist ein Seed-User
admin@jarvis.localausinit-db.sql.ensure_default_user()inmain.pynimmt schlicht den ersten User per ID alsDEFAULT_USER_IDfür alle Chat-Aktivität (in der Praxis also dieseradmin-Seed-User, nicht ein separat angelegter "jarvis-service"-User, obwohl der Code-Pfad dafür existiert)
conversations / messages (init-db.sql)
- Chat-Verlauf, Multi-Turn über
conversation_id messages.tokens_usedtrackt Claude-Token-Verbrauch pro Antwort
tasks (init-db.sql)
- Tabelle existiert, wird aber von den
/api/v1/tasks-Endpoints noch NICHT genutzt (die sind aktuell Stubs mit hartcodierten Werten, siehe "API Endpoints" unten) - offener Punkt für Phase 4b
documents + document_chunks (init-db.sql + migrations/002_document_chunks.sql)
- Knowledge Base fürs RAG:
documentshält Titel/Volltext,document_chunksdie 768-dimpgvector-Embeddings (Ollamanomic-embed-text) pro Chunk ivfflat-Index wurde wieder entfernt (003_drop_low_data_ivfflat_index.sql), da er bei wenig Daten 0 Treffer lieferte - aktuell Sequential Scan
weather_cache (migrations/004_weather_cache.sql)
- Wird ausschließlich vom n8n-Workflow "Wetter Crailsheim" befüllt (Cache,
kein Live-API-Call aus
main.py)
email_cache (migrations/005_email_cache.sql)
- Wird ausschließlich vom n8n-Workflow "Neue E-Mails Cache" befüllt (Absender/Betreff/Empfangsdatum, keine Volltexte). Der Chat greift für Live-Anfragen separat direkt per IMAP zu, nicht über diesen Cache
audit_logs (init-db.sql)
- Tabelle existiert, wird aber aktuell von keinem Code-Pfad beschrieben (vorbereitet für spätere Compliance-Anforderungen)
Redis
- Läuft und wird im Health-Check geprüft (
check_redis()), im Code aber noch nirgends für Sessions/Caching/Queues genutzt - reiner Platzhalter für spätere Erweiterung
🚀 API Endpoints
Alle /api/v1/*-Routen (ausser keine - /health ist die einzige offene
Route) verlangen den Header X-Admin-Key: <API_KEY_ADMIN>.
Health
GET /health # Oeffentlich, kein Header noetig
GET /api/v1/admin/stats # Conversations/Tasks/Documents-Zaehler
GET /api/v1/admin/health/detailed # Postgres/Redis/Milvus(TCP-Check)/Ollama/n8n
Chat (Claude, mit Tool Use für Kalender + E-Mail)
POST /api/v1/chat
Body: {"conversation_id": 1, "message": "...", "context": {}}
-> {"conversation_id", "response", "tokens_used", "timestamp"}
GET /api/v1/conversations/{id} # Voller Nachrichtenverlauf
Claude kann in run_chat_completion() bis zu MAX_TOOL_ROUNDS = 5 Tool-Runden
hintereinander ausführen: list_calendar_events, create_calendar_event,
update_calendar_event, delete_calendar_event (Löschen nur nach expliziter
Chat-Bestätigung), list_recent_emails, send_email (Senden nur nach
expliziter Chat-Bestätigung).
Kalender
GET /api/v1/calendar/events?days=14 # Naechste Termine (Nextcloud CalDAV)
Wetter
GET /api/v1/weather # Neuester Cache-Eintrag (503 wenn leer)
GET /api/v1/emails?limit=10 # Neueste gecachte Mails ([] wenn leer, kein 503)
Tasks (⚠️ noch nicht mit Postgres verbunden - TODO)
POST /api/v1/tasks # Stub: gibt immer id=1 zurueck, speichert nichts
GET /api/v1/tasks?status=pending # Stub: gibt immer leere Liste zurueck
Documents (Knowledge Base)
POST /api/v1/documents?title=...&content=...&document_type=...
# Chunking + Ollama-Embedding + Insert
GET /api/v1/documents?query=...&limit=10
# Vector-Similarity-Suche ueber document_chunks
Workflows (⚠️ noch nicht mit n8n verbunden - TODO)
POST /api/v1/workflows/trigger # Stub: ruft n8n nicht wirklich auf
🔐 Security
Es gibt kein vollwertiges Auth-System mit Login pro Nutzer. Stattdessen:
- Frontend-Login = ein geteiltes Secret (
API_KEY_ADMIN), das im Browser inlocalStorageliegt und bei jedem Request alsX-Admin-Key-Header mitgeschickt wird (require_admin_key-Dependency inmain.py) - Der
admin-User in derusers-Tabelle (ausinit-db.sql) ist nur ein DB-Seed für dieuser_id-Fremdschluessel, kein aktives Login - das Feldpassword_hashwird von keinem Code-Pfad geprüft - Für ein echtes Multi-User-System (eigene Logins, Rollen) wäre eine separate Architektur-Runde nötig - bewusst "Out of Scope" laut Frontend-Spec
Secrets (alle in .env auf dem VPS, nicht im Repo)
- API_KEY_ADMIN: Shared Secret fürs Frontend-Login + alle geschützten API-Routen
- DB_PASSWORD: Postgres-Passwort
- CLAUDE_API_KEY: Anthropic API Key
- NEXTCLOUD_APP_PASSWORD: Nextcloud CalDAV App-Passwort
- EMAIL_PASSWORD: IMAP/SMTP-Passwort für kontakt@mbo-tech-it.de
📊 Monitoring & Logs
# Real-time Logs
docker compose logs -f
# Logs für spezifischen Service
docker compose logs -f jarvis-api
# Alte Logs anschauen
docker logs --tail 100 jarvis-api
# System Resources
docker stats
🛠️ Troubleshooting
Container startet nicht
docker compose logs jarvis-api
docker compose restart jarvis-api
docker compose down && docker compose up -d
Database Connection Error
docker exec jarvis-postgres pg_isready -U jarvis
docker exec jarvis-postgres psql -U jarvis -d jarvis -c "SELECT 1"
API antwortet nicht
docker compose ps
curl -v http://localhost:8000/health
docker compose logs jarvis-api
Frontend zeigt eine neue Aenderung nicht an, obwohl deployt
web/nginx.conf setzt index.html auf no-cache und /assets/* auf
immutable - trotzdem: harter Reload (Strg+Shift+R) probieren, bevor man
tiefer sucht. Ursache war einmal ein fehlender Cache-Header (siehe Phase 4d).
n8n-Workflow läuft nicht wie erwartet
Executions-Tab des jeweiligen Workflows in der n8n-UI ansehen (zeigt Input/ Output pro Node) - schneller als Logs raten.
📈 Entwicklungsverlauf (chronologisch)
Phase 1: Grundsetup ✅
- Docker Stack deployed, alle Kern-Services laufen, Datenbank initialisiert, API verfügbar
Phase 2: KI-Integration ✅
- Claude API Key eingetragen (console.anthropic.com, separat vom Claude Pro Abo)
- Claude Integration in API (Multi-Turn ueber
conversation_id) - Token-Tracking implementiert (
tokens_usedpro Message + Response) - Postgres-Persistenz fuer Conversations/Messages
- Echte Health-Checks (Postgres, Redis, Ollama, n8n; Milvus als TCP-Check vorbereitet)
Phase 3a: Knowledge Base ✅
- pgvector-Extension in Postgres (Image gewechselt auf
pgvector/pgvector:pg16) document_chunks-Tabelle (768-dim Embeddings, Chunking 1000/100 Zeichen Overlap)- Embeddings via Ollama
nomic-embed-text(lokal, keine externen Kosten) POST/GET /api/v1/documentsfunktionsfaehig- Bug gefunden+gefixt:
ivfflat-Index lieferte bei wenig Daten 0 Treffer - Index vorerst entfernt, Sequential Scan aktiv - Follow-up:
ivfflat/hnsw-Index neu anlegen, sobald genug Dokumente vorhanden sind
Phase 3b: Frontend ✅
- React/Vite Web UI (
jarvis-webContainer, nginx-served) unter https://jarvis.mbo-tech-it.de - Shared-Secret-Login (wiederverwendet
API_KEY_ADMIN, HeaderX-Admin-Key) - Chat Interface (Multi-Turn) + Dashboard (Stats + Health-Tabelle)
- API auf eigene Subdomain umgezogen: https://api.jarvis.mbo-tech-it.de
- Bug gefixt (13.09.2026): Chat verlor Verlauf bei Tab-Wechsel/Reload, da
conversationIdnur im React-State lag. Fix:conversationIdinlocalStorage, Verlauf wird beim Mounten viaGET /api/v1/conversations/{id}wiederhergestellt (web/src/components/Chat.tsx) - Vollwertiges User-/Auth-System (Login pro Nutzer, Rollen) - weiterhin offen
Phase 4a: Wetter-Widget ✅ (erster echter n8n-Workflow)
- n8n Owner-Account eingerichtet (
jonny@mbo-tech-it.de) - n8n-Workflow "Wetter Crailsheim" (id
BwNCJ2TkuZfqUzst): Schedule-Trigger (alle 30 Min) -> Open-Meteo API (kein Key noetig) -> Code-Node (WMO-Code -> deutscher Text) -> Postgres-Insert inweather_cache - n8n-Credential "JARVIS Postgres" (zeigt auf dieselbe
jarvis-DB wie die API) GET /api/v1/weatherliest die neueste ZeileWeatherWidgetoben rechts in der Frontend-Nav-Leiste
Phase 4d: Nextcloud-Kalender-Integration ✅
- CalDAV-Zugriff auf
https://cloud.ffw-onza.de/.../ffw-onza-alle/via App-Passwort, Python-Librarycaldav GET /api/v1/calendar/events+ "Naechste Termine"-Widget im Dashboard- Chat kann Kalender abfragen, Termine anlegen und verschieben (direkt,
ohne Rueckfrage) sowie loeschen (nur nach Bestaetigung im Chat) -
Claude Tool Use mit
list_calendar_events/create_calendar_event/update_calendar_event/delete_calendar_event - Bug gefixt (13.09.2026):
run_chat_completionunterstuetzte nur eine Tool-Runde - "Termin verschieben" braucht aber zwei (erst uid perlist_calendar_eventsfinden, dannupdate_calendar_event), die zweite Runde wurde still verworfen (leere Antwort). Jetzt eine echte Schleife (MAX_TOOL_ROUNDS = 5) - Bug gefixt: neu angelegte Termine landeten als UTC statt Europe/Berlin
(2h Verschiebung) - naive Datumswerte werden jetzt explizit lokalisiert
(
_as_calendar_local) - Bug gefixt:
web/nginx.confhatte keine Cache-Header -index.htmlwurde vom Browser gecacht, wodurch ein Deploy im Browser nicht ankam, obwohl der Server bereits den neuen Build auslieferte. Jetzt:index.html=no-cache,/assets/*=immutable
Phase 4e: Sprach-Ein-/Ausgabe im Chat ✅
- Mikrofon-Button (🎤) nutzt die Browser-eigene Web Speech API
(
SpeechRecognition,de-DE) - reine Frontend-Loesung, blendet sich selbst aus, wenn der Browser das nicht unterstuetzt (v.a. Firefox) - Assistant-Antworten werden automatisch per
SpeechSynthesisvorgelesen, Standard "an"; Mute-Button (🔊/🔇) merkt sich Zustand inlocalStorage(jarvis_speech_muted) - Neues Modul
web/src/speech.tsbuendelt beide APIs (nach Vorbild vonapi.ts) - Bug gefixt (13.09.2026):
continuous=falsebeendete die Erkennung bei jeder Sprechpause. Jetztcontinuous=truemit automatischem Neustart bei Chrome's internem Session-Timeout (akkumuliert Text ueber Neustarts hinweg, damit nichts verloren geht) - Sprachausgabe filtert vor dem Vorlesen: Emojis (inkl. Zahlen-Emoji wie
1⃣2⃣3⃣), Markdown-Formatierung (
**fett**,#Ueberschriften) und dekorative Trennlinien/Tabellenzeichen (---,═══,|) - siehecleanForSpeech()inweb/src/speech.ts
Phase 4f: E-Mail-Integration ✅
- Postfach
kontakt@mbo-tech-it.de(IMAPmx2f35.netcup.net:143STARTTLS, SMTPmx2f35.netcup.net:465implizites TLS) via Python-Standardbibliothek (imaplib,smtplib,email) angebunden - keine neue Dependency - Chat-Tools
list_recent_emails(liest live per IMAP,BODY.PEEKdamit der Lese-Status nicht veraendert wird, RFC-2047-Betreffs dekodiert) undsend_email(SMTP_SSL) inrun_chat_completion(), analog zum Kalender.send_emailverlangt wiedelete_calendar_eventimmer erst eine Bestaetigung im Chat, bevor tatsaechlich versendet wird - n8n-Workflow "Neue E-Mails Cache" (id
VaAQdw18ElYWkEfr, aktiv): eingebauterEmail Trigger (IMAP)-Node (postProcessAction: "nothing", damit das Cachen den echten Lese-Status im Postfach nicht veraendert) -> Postgres-Insert inemail_cache(nur Metadaten, keine Volltexte) GET /api/v1/emailsliest die neuesten Zeilen; leerer Cache liefert[]statt 503 (anders als beim Wetter kein Fehlerzustand)EmailWidget("Neue E-Mails") im Dashboard, nach demselben Muster wieCalendarWidget/WeatherWidget- Live end-to-end getestet: Chat hat echte Inbox-Mails aufgelistet,
Testmail per Chat mit Bestaetigungsdialog versendet und im Postfach
verifiziert, n8n-Workflow hat dieselbe Mail in
email_cacheerfasst, Dashboard-Widget zeigt sie an - Kleiner Fix waehrend der Verifikation: von JARVIS selbst versendete
Mails hatten keinen
Date-Header (smtplib/EmailMessage setzt den nicht automatisch) -_send_email_syncsetzt jetztDateundMessage-ID - Out of Scope (siehe Spec): Anhaenge, Antworten/Weiterleiten, Loeschen/ Verschieben von Mails, mehrere Postfaecher/Ordner
Phase 4b: Weitere Automation ⏳ (offen)
POST/GET /api/v1/tasksan die vorhandenetasks-Tabelle anbinden (aktuell Stub)POST /api/v1/workflows/triggertatsaechlich an die n8n-API anbinden (aktuell Stub)- Weitere n8n Business-Workflows definieren (Kundenbericht-Automation o.ä.)
Phase 5: Production ⏳ (offen)
- Backup-Strategie (Postgres-Dumps automatisieren, aktuell nur manuell per
pg_dump) - Monitoring & Alerts (aktuell nur manuelles Ansehen von
/api/v1/admin/health/detailed) - Sicherheits-Hardening / echtes Multi-User-Auth-System
📞 Kontakt & Support
Owner: Jonny (Markus) Email: jonny@mbo-tech-it.de Company: MBO-Tech-IT Location: Crailsheim, Baden-Württemberg
📚 Dokumentation & Links
Spezifikationen und Implementierungspläne aller Phasen liegen lokal unter
docs/superpowers/specs/ und docs/superpowers/plans/.
🎯 Quick Reference
Start JARVIS
cd /home/jarvis-core/jarvis
docker compose up -d
Check Status
docker compose ps
curl http://localhost:8000/health
View Logs
docker compose logs -f
Backend-Code aktualisieren
scp -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key \
"Claude outputs/main.py" jarvis-core@72.61.186.98:/home/jarvis-core/jarvis/api/main.py
ssh -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key jarvis-core@72.61.186.98 \
"cd /home/jarvis-core/jarvis && docker compose restart jarvis-api"
Frontend-Code aktualisieren
scp -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key -r \
web/src jarvis-core@72.61.186.98:/home/jarvis-core/jarvis/web/
ssh -F /dev/null -o IdentitiesOnly=yes -i ~/.ssh/jarvis_core_key jarvis-core@72.61.186.98 \
"cd /home/jarvis-core/jarvis && docker compose build jarvis-web && docker compose up -d jarvis-web"
Backup Database
docker exec jarvis-postgres pg_dump -U jarvis jarvis > backup.sql
🎉 JARVIS ist bereit!
Letzte Aktualisierung: 13.09.2026 Deployment Status: ✅ LIVE