jarvis-assist/docs/superpowers/specs/2026-09-12-weather-widget-d...

6.3 KiB

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&current=temperature_2m,weather_code&timezone=Europe%2FBerlin

Antwortformat (Auszug):

{
  "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:

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):

{
  "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.