what_to_wear/docs/superpowers/specs/2026-07-11-what-to-wear-design.md
Nora 4d7ef85406 docs: Design-Spec v1 für What to Wear (WTW) + Projekt-Scaffolding
Brainstorming-Ergebnis der AI-Dev-Method (Phase 0/Design):
- HACS-Custom-Integration what_to_wear, Open-Source, standalone in Kunden-HA
- Kleiderschrank-Inventar (Sub-Entries), Regeln→Anforderungen→Matcher, optionaler LLM-Ton (BYO-Key)
- Wetter v1 aus HA-Wetter-Entität; Open-Meteo/LagerLens/CRUD-Karte = v1.1
- LEDGER inkl. Kritiker-Konsultation (gpt-5.6-luna-pro) zur Wetterquelle

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 20:18:10 +00:00

157 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# What to Wear (WTW) — Design-Spec v1
- **Datum:** 2026-07-11
- **Status:** Entwurf zur Review (Brainstorming-Ergebnis; Keim für den BMAD-PRD)
- **Methode:** AI-Dev-Method (BMAD + adversariale Reviewer-Linsen + KI-Zweitkritiker)
- **Domain / Name:** `what_to_wear` — „What to Wear (WTW)"
---
## 1. Intent (ein Satz)
Eine **quelloffene Home-Assistant-Integration**, die dem Nutzer abends sagt, **welche konkreten
Kleidungsstücke aus seinem Kleiderschrank** er für morgen rauslegen soll — deterministisch aus der
Wetterprognose abgeleitet, optional sprachlich schön formuliert, ausgespielt über Dashboard / Push / Ansage.
## 2. Problem & Zielgruppe
- **Problem:** Morgens Zeitdruck und Fehlgriffe bei der Kleidung; abends fehlt der schnelle Überblick,
was das Wetter *morgen* konkret verlangt (Regen, Frost, Wind, UV) — und was davon man überhaupt besitzt.
- **Zielgruppe:** Home-Assistant-Nutzer (DACH + international), die abends Kleidung vorbereiten —
Pendler, Eltern (Kind anziehen), Menschen mit festem Morgenritual.
- **Vertriebskontext:** Open-Source-HACS-Produkt (Reichweite/Reputation), später Upsell über einen
optionalen LagerLens-Connector (KI-Foto-Katalogisierung der Kleidung).
## 3. Umfang v1 — bewusste Nicht-Ziele (v1.1+)
**In v1:**
- HACS-Custom-Integration `what_to_wear`, Config-Flow, Options-Flow.
- Kleiderschrank-Inventar **nativ** über HA-Sub-Entries (echte Stücke mit Eigenschaften).
- `WeatherProvider`-Interface mit **einer** Implementierung: HA-Wetter-Entität.
- Pipeline: Normalizer → Regel-Engine → Matcher → (optional) LLM-Ton.
- Ausgabe: **Empfehlungs-Sensor** + Service/Event; **read-only Lovelace-Karte**; **2 Blueprints** (Push, TTS).
- Optionaler **LLM-Ton** (Bring-your-own-Key, default AUS).
- i18n **de + en**.
**Bewusst vertagt (v1.1+):**
- LagerLens-Connector als zweite Kleiderschrank-Quelle.
- Open-Meteo als zweiter `WeatherProvider`.
- Schöne CRUD-Verwaltungskarte für den Kleiderschrank (v1: native HA-UI genügt).
- Mehrere Personen/Profile; Aktivitäts-/Kalenderkontext (Termine, „heute Sport"); Wäsche-/Verfügbarkeitsstatus.
## 4. Produktform & Distribution
- Standard-HA-`custom_component` (Python, async), HACS-installierbar; MVP-Struktur:
```
custom_components/what_to_wear/ __init__.py, manifest.json, config_flow.py, coordinator.py,
sensor.py, services.yaml, strings.json, translations/{de,en}.json,
weather/ (provider-interface + ha_entity impl),
logic/ (normalize.py, rules.py, matcher.py, phraser.py)
blueprints/automation/what_to_wear/ notify_push.yaml, announce_tts.yaml
www/what-to-wear-card.js (read-only Lovelace-Karte)
```
- **Lizenz:** Vorschlag **MIT** (offene Kleinentscheidung).
- **Min-HA-Version:** Vorschlag **2024.12+** (für `weather.get_forecasts` mit `return_response=True`
und Config-Sub-Entries) — in der Architektur-Phase gegen die tatsächlich benötigten APIs verifizieren.
- Repo: **lokal** (git `master`), Remote später.
## 5. Architektur — Pipeline & Komponenten
```
WeatherProvider ─▶ ForecastNormalizer ─▶ RulesEngine ─▶ WardrobeMatcher ─▶ (opt.) LLMPhraser
RecommendationSensor ◀───────────────────────────────────┘
(User-Automation via Blueprint) ─▶ Push / TTS / Lovelace-Karte
```
- **WeatherProvider** (Interface `async get_tomorrow_forecast() -> RawForecast`): v1-Impl liest die vom
Nutzer gewählte `weather.*`-Entität via `weather.get_forecasts` (daily + hourly, `return_response=True`).
- **ForecastNormalizer:** RawForecast → **NormalizedForecast** für *morgen* (lokale TZ), interne **SI-Einheiten**,
je Feld ein „vorhanden?"-Flag. Aggregiert stündlich → Tageswerte nach lokalem Datum.
- **RulesEngine:** NormalizedForecast → Liste **Requirement** (Eigenschaft + Grund + Priorität).
- **WardrobeMatcher:** Requirements × Kleiderschrank → gewählte Stücke + Begründung + **Lücken** („keine Regenjacke").
- **LLMPhraser** (optional): formt nur den Text; bei Aus/Fehler → deterministischer Regeltext.
- **DataUpdateCoordinator:** hält das morgige Ergebnis aktuell; Benachrichtigung triggert der Nutzer per Blueprint.
### Invarianten-Spine (Keim für die Architektur-Phase)
- **INV-1 (Nie stumm):** Die Empfehlung fällt nie aus. Bei Teil-Ausfall (LLM, fehlendes Wetterfeld, leerer
Schrank) liefert der deterministische Kern trotzdem eine Empfehlung und **benennt die Lücke**.
- **INV-2 (Morgen lokal):** „Morgen" ist stets das lokale Kalenderdatum in `hass.config.time_zone` (DST-fest).
- **INV-3 (SI intern):** Interne Berechnung nur im SI-Normmodell; Quelle/Einheit/Missingness bleiben am Datum
erhalten; Werte werden **nie** aus Feldname oder Größenordnung geraten.
- **INV-4 (Geheimnisse):** LLM-Key (später LagerLens-Token) nie im Klartext in Logs/State/Attributen; nur im
HA-Config-Storage.
- **INV-5 (Keine stille Netzlast):** v1 spricht nur mit HA selbst. Externe Provider (v1.1) nur opt-in, mit
Coordinator/Timeout/Backoff/Attribution; kein stiller Provider-Wechsel.
- **INV-6 (Trennung):** Normalize / Rules / Matcher sind strikt getrennt und je einzeln testbar.
## 6. Datenmodell
- **Kleidungsstück (Sub-Entry):** `name`, `kategorie` (z. B. Jacke/Pullover/Hose/Schuhe/Accessoire/Kopf/Hand),
`waerme` 15, `wasserdicht` bool, `winddicht` bool, `formalitaet` (leger/business), `saison`/Temp-Range
(optional), `foto` (optional), `aktiv` bool.
- **NormalizedForecast (morgen):** `temp_min`, `temp_max`, `temp_gefuehlt_min/max` (°C), `regen_wkt` (%),
`regen_menge` (mm), `wind` / `boeen` (km/h), `uv_index`, `zustand` (klar/bewölkt/Regen/Schnee/Gewitter) —
**jeweils mit `vorhanden`-Flag** + Herkunft/Zeitstempel.
- **Requirement:** `eigenschaft` (z. B. `wasserdichte_aussenschicht`, `waerme_min:4`, `sonnenschutz`,
`handschuhe`, `muetze`), `grund` (menschlesbar), `prioritaet` (muss/soll/kann).
- **Recommendation:** `kurztext` (Sensor-State), `stuecke[]`, `requirements[]`, `luecken[]`, `kennwerte`, `quelle`.
## 7. Regel-Engine (illustrative Schwellwerte — final in PRD/Architektur)
> Beispielhaft, konfigurierbar; **nicht** endgültig. Kälteempfinden-Offset verschiebt Temperaturschwellen.
- `temp_gefuehlt_max < 0 °C` → `waerme_min:5`, `muetze`, `handschuhe`, `schal`.
- `08 °C` → `waerme_min:4`; `815 °C` → `waerme_min:3`; `1522 °C` → `waerme_min:2`; `> 22 °C` → `waerme_min:1`, ggf. `sonnenschutz`.
- `regen_wkt ≥ 40 %` **oder** `regen_menge ≥ 1 mm` → `wasserdichte_aussenschicht`, `feste_schuhe`.
- `boeen ≥ 40 km/h` → `winddicht`.
- `uv_index ≥ 6` → `sonnenschutz` (Brille/Kopfbedeckung).
- `zustand = Schnee` → `waerme_min:4`, `wasserdicht`, `profilsohle`.
## 8. Matcher
- Wählt je Requirement das am besten passende **aktive** Stück (Priorität muss > soll > kann; bei Gleichstand
nächstpassende Wärme/Formalität).
- Fehlt ein Stück für ein `muss`/`soll`-Requirement → **Lücke** in `luecken[]` (z. B. „Für morgen wäre eine
Regenjacke ideal — keine im Schrank hinterlegt.").
- Ergebnis ist erklärbar: jedes Stück trägt seinen Grund (welches Requirement es erfüllt).
## 9. LLM-Ton (optional, Bring-your-own-Key)
- Default **AUS**. Nutzer trägt eigenen Key (OpenAI/Anthropic) im Options-Flow ein → nur im Config-Storage.
- Eingabe an das LLM: die **strukturierte** Recommendation (Stücke + Gründe + Kennwerte) + Zielsprache.
Aufgabe: nur **umformulieren**, keine neuen Fakten, keine geänderte Stückauswahl.
- **Fehler/Timeout/kein Key → deterministischer Regeltext** (INV-1). LLM ändert nie die Auswahl.
## 10. Ausgabe: Sensor / Service / Karte / Blueprints
- **Sensor** `sensor.what_to_wear`: `state` = Kurzempfehlung; `attributes` = `stuecke`, `requirements`,
`luecken`, `kennwerte`, `quelle`, `stand`.
- **Service/Event** `what_to_wear.recommend` (manuelles Neuberechnen; feuert Event mit dem Ergebnis).
- **Lovelace-Karte** (read-only): zeigt morgige Empfehlung + Stücke + Lücken dauerhaft.
- **Blueprints:** `notify_push` (Nutzer wählt notify-Ziel + Uhrzeit), `announce_tts` (Nutzer wählt
media_player + Auslöser). Import ist ein geführter HA-Klick-Flow → laienfreundlich, ohne notify-Logik
in der Integration.
## 11. Konfiguration
- **Config-Flow (Ersteinrichtung):** Wetter-Entität wählen (Entity-Selector, Pflicht; Fehler wenn keine da),
Sprache (Default = HA-Sprache), Kälteempfinden-Offset.
- **Options-Flow:** Schwellwerte/Offsets, optionaler LLM-Key + Provider (default aus).
- **Sub-Entries:** Kleidungsstücke anlegen/bearbeiten/löschen in der nativen HA-UI.
## 12. Fehlerbehandlung & Edge Cases (aus dem Kritiker-Review)
- Keine geeignete `weather.*`-Entität → klarer Config-Fehler, kein Raten (INV-1/Config).
- Wetterfeld fehlt → Regel greift **degradiert** + Hinweis; „fehlend" ≠ „0" (INV-3).
- „Morgen"/DST strikt in lokaler TZ (INV-2).
- LLM-Fehler/Timeout/kein Key → Fallback auf Regeltext (INV-1).
- Leerer/lückenhafter Schrank → Anforderung + Lücke nennen statt schweigen (INV-1).
- Einheiten (°C/°F, km/h/mph, mm/inch) bewusst konvertieren; Open-Meteo-Wettercode ↔ HA-`condition` per Mapping-Tabelle (v1.1).
## 13. i18n
- HA-Translations für UI (`de`, `en`); Empfehlungstext folgt der HA-Sprache; Regeltext-Bausteine je Sprache.
## 14. Tests & echte Verifikation (Methoden-Pflicht)
- **Unit:** Normalizer/Rules/Matcher mit Wetter-Fixtures (Regen, Frost, Hitze, DST-Tag, fehlende Felder, leerer Schrank).
- **Integration:** `pytest-homeassistant-custom-component` (Config-Flow, Sensor, Service).
- **Echte E2E:** Wegwerf-HA-Docker-Instanz — Integration installieren → Wetter-Entität + Beispielschrank →
Sensor prüfen → Blueprint-Push real auslösen. Negativfälle (keine Wetter-Entität, LLM-Key falsch).
- **TDD:** Test rot → Code → grün → volle Suite → Commit (ein Commit pro Story). qwen/Cloud-Review nach jeder Story.
## 15. Offene Punkte / Annahmen (in PRD/Architektur klären)
- Lizenz (Vorschlag MIT). Min-HA-Version (Vorschlag 2024.12+, gegen APIs verifizieren).
- Ob v1 die Sub-Entry-CRUD-UX von HA praktisch trägt (sonst früher CRUD-Karte).
- Genaue Schwellwerte/Regeln (Kap. 7 illustrativ).
- Foto-Speicherung bei nativem Kleiderschrank (Pfad/Umfang) — v1 optional/minimal.
## 16. Roadmap v1.1+
LagerLens-Connector (Foto-Katalog) · Open-Meteo-Provider · CRUD-Verwaltungskarte · Mehrpersonen-Profile ·
Aktivitäts-/Kalenderkontext · Wäsche-/Verfügbarkeitsstatus.