diff --git a/README.md b/README.md
new file mode 100644
index 0000000..512a151
--- /dev/null
+++ b/README.md
@@ -0,0 +1,641 @@
+# Smart-Dashboard
+
+Die Anzeige und Bedienung des Hauses: Grundrisse mit Messwerten, Solar- und
+Verbrauchsverläufe, das Fahrzeug, die Automatiken, die Einstellungen. Alles,
+was einen offenen Browser braucht, liegt hier.
+
+Gegenstück ist das Repo **`admin/SolarManager`** unter
+`/volume1/homes/wagner/SolarManager` — dort laufen die Hintergrundprozesse,
+die Messwerte einsammeln und die Automatiken ausführen. Beide Seiten reden
+über zwei Dinge miteinander und nie direkt: den **MQTT-Broker** für alles
+Aktuelle, die **Datenbanken** für alles, was bleiben soll. Wer wissen will,
+woher eine Zahl ursprünglich kommt, liest die README dort; hier steht, was
+mit ihr im Browser passiert.
+
+Dieses Verzeichnis ist zugleich der Web-Root der NAS
+(`/volume1/web/smart`, ausgeliefert unter `https://nas.el-wa.org/smart`).
+Der Arbeitsordner *ist* die laufende Anwendung — jede gespeicherte Datei ist
+sofort live.
+
+---
+
+## Inhalt
+
+1. [Auf einen Blick](#auf-einen-blick)
+2. [Wie eine Seite entsteht](#wie-eine-seite-entsteht)
+3. [Zwei Wege für Daten](#zwei-wege-für-daten)
+4. [Die Seitenkarte](#die-seitenkarte)
+5. [Die JavaScript-Schicht](#die-javascript-schicht)
+6. [Die PHP-Schicht](#die-php-schicht)
+7. [Die Datenbanken](#die-datenbanken)
+8. [Vier Bausteine im Detail](#vier-bausteine-im-detail)
+9. [Wiederkehrende Bauteile und Konventionen](#wiederkehrende-bauteile-und-konventionen)
+10. [Wo fange ich an, wenn ich … ändern will](#wo-fange-ich-an-wenn-ich--ändern-will)
+11. [Entwickeln und Prüfen](#entwickeln-und-prüfen)
+
+---
+
+## Auf einen Blick
+
+```
+smart/
+├── index.php Router: Anmeldung prüfen, Seite auswählen, drei Includes
+├── helper.php Session, Heimnetzerkennung, checkLogin(), httpGetJson()
+├── authServer.php Passkeys (WebAuthn): Registrierung und Anmeldung
+├── addUser.php Einmal-Link zum Anlegen eines neuen Schlüssels
+├── .htaccess sperrt .git, *.py, *.sql, *.ini … für den Browser
+│
+├── restricted/ Vorlagen (was man sieht) und Modelle (was es weiß)
+│ ├── header.php footer.php Rahmen jeder Seite, Menü, Skript-Einbindung
+│ ├── home.php solar.php heat.php history.php
+│ ├── skoda.php weather.php settings.php logs.php ← die acht Seitenvorlagen
+│ ├── rooms.php Räume, Etagen, Kachelwerte, Symbole
+│ ├── costs.php Preistabellen + solarDb()
+│ ├── automations.php Automatiken, Gerätekatalog + meshDb()
+│ ├── kacheln.php Anzeigewerte der Home-Kacheln (Modell zur Maske)
+│ ├── roomControls.php Bedienelemente des Raum-Modals
+│ ├── commands.php ein Kommando tatsächlich abschicken
+│ ├── wallboxen.php beide Wallboxen über MQTT
+│ ├── logdateien.php Logdateien lesen
+│ ├── aussenplan.php Schrägbild des Außengeländes (SVG, gerechnet)
+│ ├── reiter.php das eine Reiter-Bauteil der ganzen Seite
+│ ├── config.php Zahlen, die an der Wirklichkeit hängen
+│ ├── mysql.php Zugangsdaten — NICHT im Git (mysql.php.example)
+│ └── deviceDiscovery/ Python: Geräte suchen und in homeMesh eintragen
+│
+├── ajax/ Endpunkte. Verteiler, keine Logik (Ausnahmen unten)
+├── js/solar/ der eigene JavaScript-Code
+├── js/ Fremdbibliotheken, alle lokal (kein CDN)
+├── css/solar.css das eigene Stylesheet (Theme + alle Bauteile)
+├── assets/img/ Grundriss-Renderings OG/EG/UG/AG, Icons
+├── tiles/ Kartenkacheln-Zwischenspeicher (nicht im Git)
+└── *.sql Schema-Dateien zum Nachziehen von Hand
+```
+
+---
+
+## Wie eine Seite entsteht
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant B as Browser
+ participant I as index.php
+ participant H as helper.php
+ participant T as Vorlage + Modelle
+ participant F as footer.php
+
+ B->>I: GET index.php?action=home&floor=OG
+ I->>H: checkLogin()
+ H-->>I: Heimnetz? sonst Passkey-Sitzung
+ Note over I: $pages[...] wählt Vorlage,
Bibliotheken und Seitenskripte
+ I->>T: include header.php
+ T-->>B: Kopf und Menü, gebaut aus $floors
+ I->>T: include restricted/(seite).php
+ T-->>B: Karten, SVG, eingebettete JSON-Daten
+ I->>F: include footer.php
+ F-->>B: Bootstrap, ggf. mqtt.js/Chart.js/Leaflet,
common.js, dann die Seitenskripte
+ B->>B: Skripte verbinden sich mit Broker und holen per fetch nach
+```
+
+**Anmeldung.** `helper.php` kennt zwei Wege. Aus dem Heimnetz
+(`LOCAL_NETWORKS`, geprüft binär über `inet_pton`, ausschließlich anhand von
+`REMOTE_ADDR` — Weiterleitungs-Header sind fälschbar und werden bewusst
+ignoriert) ist man ohne Anmeldung drin. Von außen zählt ein Passkey:
+`authServer.php` mit der WebAuthn-Bibliothek unter `restricted/WebAuthn`,
+Schlüssel in der Datenbank `Logins`. Ein neuer Schlüssel entsteht nur über
+einen Einmal-Link (`addUser.php`, Tabelle `addUser`, eine Minute gültig).
+
+**Die Seitentabelle** in `index.php` ist die einzige Stelle, an der steht,
+welche Seite es gibt und was sie braucht:
+
+```php
+"home" => ["template" => "home.php", "mqtt" => true, "charts" => false,
+ "meteogram" => false, "leaflet" => false,
+ "scripts" => ["js/solar/autoActionFuncs.js", "js/solar/homeMQTT.js"]],
+```
+
+`footer.php` lädt daraus die Bibliotheken — Chart.js nur wo gezeichnet wird,
+mqtt.js nur wo Livewerte laufen, Leaflet nur auf der Fahrzeugseite. Danach
+kommt immer `common.js` und dann die Seitenskripte, jeweils mit
+`?v=`, damit ein Browser nie eine alte Fassung behält.
+
+**Vorlage und Modell sind getrennt.** Eine Seitenvorlage baut Markup und ruft
+dafür Funktionen aus den Modelldateien; die Modelldateien enthalten kein
+Markup außer dort, wo sie ein Bedienelement zeichnen (`roomControls.php`,
+`reiter.php`). Die Endpunkte in `ajax/` benutzen dieselben Modellfunktionen —
+so kann eine Maske nicht etwas anderes behaupten als der Endpunkt, der sie
+speichert.
+
+---
+
+## Zwei Wege für Daten
+
+```mermaid
+flowchart LR
+ subgraph Browser
+ JS["js/solar/*.js"]
+ SVG["SVG-Grundriss
Diagramme
Masken"]
+ end
+
+ BROKER{{"MQTT-Broker
wss://mqtt.nas.el-wa.org:443"}}
+ AJAX["ajax/*.php"]
+ MODELL["restricted/*.php
Modell-Schicht"]
+ SOLARLOG[("solarLog
Verlauf")]
+ HOMEMESH[("homeMesh
Geräte, Automatiken")]
+ GERAETE["Geräte
Tahoma · WLED · Shelly · Wallboxen"]
+
+ BROKER -->|"laufende Werte"| JS
+ JS --> SVG
+ JS <-->|"fetch: Verlauf, Struktur, Masken"| AJAX
+ AJAX --> MODELL
+ MODELL --> SOLARLOG
+ MODELL --> HOMEMESH
+ MODELL -.->|"Kommandos"| BROKER
+ MODELL -.->|"HTTP · Tahoma · WLED"| GERAETE
+
+ classDef speicher fill:#eaf5ee,stroke:#6fa981
+ classDef code fill:#fff6e5,stroke:#d0a548
+ class SOLARLOG,HOMEMESH,BROKER speicher
+ class JS,AJAX,MODELL code
+```
+
+Die Regel dahinter, und sie gilt ohne Ausnahme:
+
+| Was | Weg | Warum |
+|---|---|---|
+| Aktueller Messwert (Leistung, Temperatur, Ladestand) | **MQTT über `wss`, direkt vom Broker** | Er weiß es ohnehin, und er sagt es von selbst — kein Nachfragen im Takt |
+| Verlauf, Statistik, Gerätelisten, Formulare | **`fetch` auf `ajax/*.php`** | Das weiß nur die Datenbank |
+| Jeder Knopfdruck (schalten, speichern, Fahrzeugbefehl) | **immer über den Server** | Zugangsdaten dürfen die Seite nicht verlassen, und der Broker ist von außen nicht erreichbar |
+
+Der Browser abonniert je nach Seite `solarManager/#`, `weatherStation/#`,
+`wattpilot/#`, `go-eCharger/#`, `Gartenwasser/#` und — auf der Home-Seite —
+genau die Topics, die auf den Kacheln stehen (`tileTopics()` in `rooms.php`).
+
+---
+
+## Die Seitenkarte
+
+| Seite (`?action=`) | Vorlage | Seitenskripte | holt per fetch | hört auf MQTT |
+|---|---|---|---|---|
+| `solar` (Vorgabe) | `solar.php` | `jahresstatistik.js`, `solarMQTT.js` | `getProdData`, `getConsData`, `getForecastData`, `getSunrise`, `getStats`, `carEG`, `carOG`, `heater`, `watering` | `solarManager/#`, `weatherStation/#`, `wattpilot/#`, `go-eCharger/#`, `Gartenwasser/#` |
+| `home` | `home.php` | `autoActionFuncs.js`, `homeMQTT.js` | `room.php`, `AutoAction.php` | die Topics der Kacheln, `Raumtemp/#` |
+| `heat` | `heat.php` | `heatMQTT.js` | `getHeaterData`, `getWaterData`, `getSunrise` | `solarManager/#`, `weatherStation/#`, Wallbox-Topics |
+| `history` | `history.php` | `jahresstatistik.js`, `historyMQTT.js` | `energyHistory` (6 ×), `getStats` | — |
+| `skoda` | `skoda.php` | `skodaMQTT.js` | `skoda.php?was=…`, `skodaCmd.php`, `tile.php` | `solarManager/#` |
+| `weather` | `weather.php` | `weatherMQTT.js` | nichts — das Meteogramm ist ein fremdes Dokument im `