jarvis-assist/Claude outputs/JARVIS_HANDOFF.md

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.de auf mx2f35.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.local aus init-db.sql. ensure_default_user() in main.py nimmt schlicht den ersten User per ID als DEFAULT_USER_ID für alle Chat-Aktivität (in der Praxis also dieser admin-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_used trackt 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: documents hält Titel/Volltext, document_chunks die 768-dim pgvector-Embeddings (Ollama nomic-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)

E-Mail

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 in localStorage liegt und bei jedem Request als X-Admin-Key-Header mitgeschickt wird (require_admin_key-Dependency in main.py)
  • Der admin-User in der users-Tabelle (aus init-db.sql) ist nur ein DB-Seed für die user_id-Fremdschluessel, kein aktives Login - das Feld password_hash wird 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_used pro 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/documents funktionsfaehig
  • 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-web Container, nginx-served) unter https://jarvis.mbo-tech-it.de
  • Shared-Secret-Login (wiederverwendet API_KEY_ADMIN, Header X-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 conversationId nur im React-State lag. Fix: conversationId in localStorage, Verlauf wird beim Mounten via GET /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 in weather_cache
  • n8n-Credential "JARVIS Postgres" (zeigt auf dieselbe jarvis-DB wie die API)
  • GET /api/v1/weather liest die neueste Zeile
  • WeatherWidget oben 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-Library caldav
  • 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_completion unterstuetzte nur eine Tool-Runde - "Termin verschieben" braucht aber zwei (erst uid per list_calendar_events finden, dann update_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.conf hatte keine Cache-Header - index.html wurde 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 SpeechSynthesis vorgelesen, Standard "an"; Mute-Button (🔊/🔇) merkt sich Zustand in localStorage (jarvis_speech_muted)
  • Neues Modul web/src/speech.ts buendelt beide APIs (nach Vorbild von api.ts)
  • Bug gefixt (13.09.2026): continuous=false beendete die Erkennung bei jeder Sprechpause. Jetzt continuous=true mit 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 (---, ═══, |) - siehe cleanForSpeech() in web/src/speech.ts

Phase 4f: E-Mail-Integration

  • Postfach kontakt@mbo-tech-it.de (IMAP mx2f35.netcup.net:143 STARTTLS, SMTP mx2f35.netcup.net:465 implizites TLS) via Python-Standardbibliothek (imaplib, smtplib, email) angebunden - keine neue Dependency
  • Chat-Tools list_recent_emails (liest live per IMAP, BODY.PEEK damit der Lese-Status nicht veraendert wird, RFC-2047-Betreffs dekodiert) und send_email (SMTP_SSL) in run_chat_completion(), analog zum Kalender. send_email verlangt wie delete_calendar_event immer erst eine Bestaetigung im Chat, bevor tatsaechlich versendet wird
  • n8n-Workflow "Neue E-Mails Cache" (id VaAQdw18ElYWkEfr, aktiv): eingebauter Email Trigger (IMAP)-Node (postProcessAction: "nothing", damit das Cachen den echten Lese-Status im Postfach nicht veraendert) -> Postgres-Insert in email_cache (nur Metadaten, keine Volltexte)
  • GET /api/v1/emails liest die neuesten Zeilen; leerer Cache liefert [] statt 503 (anders als beim Wetter kein Fehlerzustand)
  • EmailWidget ("Neue E-Mails") im Dashboard, nach demselben Muster wie CalendarWidget/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_cache erfasst, 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_sync setzt jetzt Date und Message-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/tasks an die vorhandene tasks-Tabelle anbinden (aktuell Stub)
  • POST /api/v1/workflows/trigger tatsaechlich 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


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