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¤t=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:
- Schedule Trigger: Intervall 30 Minuten.
- HTTP Request: GET auf die Open-Meteo-URL oben.
- Code (JavaScript): mapped
weather_codeaufcondition_text(Tabelle oben), reichttemperature_2m,weather_codeundcondition_textweiter. - Postgres:
INSERT INTO weather_cache (location, temperature_c, condition_code, condition_text) VALUES ('Crailsheim', ..., ..., ...). n8n's Postgres-Credential zeigt auf dieselbejarvis-Datenbank, die die API auch nutzt (gleicher Host/User/Passwort wieDATABASE_URLder 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/weatherladen. - Danach alle 5 Minuten neu laden (
setInterval, aufgeraeumt inuseEffect-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_cacheleer: Backend liefert503, 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 viaTestClient+ 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 gemocktendb_queryaufgerufen 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_cacheeine Zeile hat,GET /api/v1/weathertesten, 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.