# JARVIS Weather Widget (Phase 4a) - Design **Datum:** 2026-09-12 **Status:** Approved, bereit fuer Implementierungsplan ## Kontext Phase 3b (Web-Frontend mit Chat + Dashboard) ist live. `n8n` laeuft bereits im Stack seit Phase 2/3, wurde aber noch nie konfiguriert (kein Owner-Account, keine Workflows). Diese Spec macht n8n zum ersten Mal produktiv nutzbar: ein Workflow holt periodisch das Wetter fuer Crailsheim (Firmenstandort laut `JARVIS_HANDOFF.md`) und das Frontend zeigt es oben rechts in der Nav-Leiste an. ## Datenfluss ``` n8n (Schedule-Trigger, alle 30 Min) -> HTTP Request: Open-Meteo API (kein API-Key noetig) -> Code-Node: WMO-Wettercode -> deutscher Text -> Postgres-Node: INSERT INTO weather_cache JARVIS-API: GET /api/v1/weather liest die neueste Zeile aus weather_cache Frontend: WeatherWidget faengt beim Laden + alle 5 Min neu ab ``` ## Wetterquelle: Open-Meteo Kein API-Key noetig (kostenlos, keine Registrierung). Endpoint: ``` https://api.open-meteo.com/v1/forecast?latitude=49.1372&longitude=10.0674¤t=temperature_2m,weather_code&timezone=Europe%2FBerlin ``` Antwortformat (Auszug): ```json { "current": { "time": "2026-09-12T16:00", "temperature_2m": 18.4, "weather_code": 3 } } ``` WMO-Wettercode-Mapping (Open-Meteo-Standard, Teilmenge fuer die haeufigsten Faelle - vollstaendige Tabelle im Code-Node): | Code | Text | |------|------| | 0 | Klarer Himmel | | 1-2 | Ueberwiegend klar | | 3 | Bewoelkt | | 45, 48 | Nebel | | 51-57 | Nieselregen | | 61-67 | Regen | | 71-77 | Schnee | | 80-82 | Regenschauer | | 95-99 | Gewitter | | (sonst) | Unbekannt | ## Datenmodell Neue Tabelle `weather_cache`: ```sql CREATE TABLE weather_cache ( id SERIAL PRIMARY KEY, location VARCHAR(100) NOT NULL, temperature_c NUMERIC NOT NULL, condition_code INTEGER NOT NULL, condition_text VARCHAR(100) NOT NULL, fetched_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_weather_cache_fetched_at ON weather_cache(fetched_at); ``` Jeder n8n-Lauf fuegt eine neue Zeile ein (kein Update/Upsert - einfacher, und die Tabelle bleibt klein bei 30-Minuten-Intervall; alte Zeilen aufraeumen ist ein spaeteres Follow-up, kein akutes Problem bei diesem Datenvolumen). ## n8n-Workflow: "Wetter Crailsheim" n8n wurde bisher nie initialisiert (kein Owner-Account, kein API-Key fuer die n8n-REST-API). Einmaliger Setup-Schritt (per Browser, da n8n das beim ersten Aufruf erzwingt): Owner-Account anlegen, dann unter Settings -> API einen API-Key generieren. Danach wird der Workflow per n8n-REST-API (`POST /rest/workflows` bzw. `/api/v1/workflows` je nach n8n-Version, siehe Plan) als JSON-Definition angelegt und aktiviert - kein manuelles Zusammenklicken der Nodes. Workflow-Nodes: 1. **Schedule Trigger**: Intervall 30 Minuten. 2. **HTTP Request**: GET auf die Open-Meteo-URL oben. 3. **Code** (JavaScript): mapped `weather_code` auf `condition_text` (Tabelle oben), reicht `temperature_2m`, `weather_code` und `condition_text` weiter. 4. **Postgres**: `INSERT INTO weather_cache (location, temperature_c, condition_code, condition_text) VALUES ('Crailsheim', ..., ..., ...)`. n8n's Postgres-Credential zeigt auf dieselbe `jarvis`-Datenbank, die die API auch nutzt (gleicher Host/User/Passwort wie `DATABASE_URL` der API, siehe `.env`). ## Backend: `GET /api/v1/weather` Neuer Endpoint in `main.py`, durch `require_admin_key` geschuetzt (wie alle anderen `/api/v1/*`-Routen ausser `/health`): ```json { "location": "Crailsheim", "temperature_c": 18.4, "condition_text": "Bewoelkt", "fetched_at": "2026-09-12T16:00:03.123456" } ``` Wenn `weather_cache` leer ist (Workflow lief noch nicht): `503` mit Fehlermeldung "Weather data not available yet" - kein stiller Platzhalter, das Frontend zeigt das dann sichtbar als Fehler statt falscher Daten. ## Frontend: `WeatherWidget` Kleine Komponente, in der Nav-Leiste rechtsbuendig (per CSS `margin-left: auto` auf dem Widget-Container, bestehende Nav-Buttons bleiben linksbuendig). Sichtbar in beiden Ansichten (Chat + Dashboard), da die Nav-Leiste immer gerendert wird. - Beim Mount: `GET /api/v1/weather` laden. - Danach alle 5 Minuten neu laden (`setInterval`, aufgeraeumt in `useEffect`-Cleanup) - haeufiger als noetig waere reine Verschwendung, seltener als der 30-Minuten-Workflow waere unnoetig zurueckhaltend; 5 Minuten ist ein vernuenftiger Mittelweg fuer eine UI-Anzeige. - Anzeige: `18.4°C · Bewoelkt`. Bei Fehler (503 o.ae.): unauffaellige Kurzmeldung statt der Wetteranzeige (kein Popup/Alert), da es sich um ein Nice-to-have-Widget handelt, keine kritische Funktion. ## Fehlerbehandlung - Open-Meteo nicht erreichbar: n8n-Workflow-Lauf schlaegt fehl, naechster Lauf in 30 Minuten versucht es erneut. Kein Retry innerhalb eines Laufs (YAGNI - Schedule-Trigger uebernimmt das ohnehin). - `weather_cache` leer: Backend liefert `503`, Frontend zeigt Kurzmeldung. - n8n/Postgres-Verbindung fehlerhaft: sichtbar im n8n-Execution-Log (manuell pruefbar in der n8n-UI), keine gesonderte Behandlung noetig fuer dieses Nice-to-have-Feature. ## Testing - Backend: Unit-Test fuer `GET /api/v1/weather` - leere Tabelle -> 503, vorhandene Zeile -> korrektes JSON (mit einer eingefuegten Testzeile via `TestClient` + einer echten Test-Postgres-Instanz ist hier zu viel Aufwand fuer dieses kleine Feature; stattdessen wird die Query-Logik direkt getestet, indem die DB-Helper-Funktion mit einer gemockten `db_query` aufgerufen wird - siehe Plan fuer die konkrete Test-Strategie). - Frontend: kein gesonderter Unit-Test (das Widget ist eine einfache Fetch-und-Anzeige-Komponente, gleiches Muster wie `Dashboard.tsx`, das auch keinen Unit-Test hat) - Build-Check (`npm run build`) reicht, passend zum bisherigen Muster in diesem Projekt. - Manueller End-to-End-Test nach Deployment: n8n-Workflow einmal manuell ausloesen (n8n-UI "Execute Workflow" oder Warten auf den ersten Schedule-Lauf), pruefen dass `weather_cache` eine Zeile hat, `GET /api/v1/weather` testen, Widget im Browser sehen. ## Out of Scope (bewusst nicht Teil dieser Phase) - Mehrere Standorte / nutzerkonfigurierbarer Standort. - Wettervorhersage (nur aktuelles Wetter, kein Forecast-Display). - Aufraeumen alter `weather_cache`-Zeilen (Retention-Policy) - spaeteres Follow-up, kein Problem bei aktuellem Datenvolumen. - Wetter-Icons/Grafiken - nur Text.