Am Monatsersten bekommt jeder Benutzer, der im Vormonat geladen hat und eine
Adresse hinterlegt hat, seinen eigenen Bericht als PDF. Wer nicht geladen hat,
bekommt nichts, das war die Vorgabe.
Der Bericht war bisher nur ein Handler. Herausgeloest sind jetzt collect() und
build_pdf(), sodass Weboberflaeche und Versand denselben Weg nehmen und die
Zahlen in Mail und Bildschirm nicht auseinanderlaufen koennen. Die Monatsgrenzen
rechnet month_bounds() an einer Stelle.
Zwei Dinge, die den Betrieb betreffen:
Der Versand ist aus, solange kein [mail]-Abschnitt in der config.toml steht.
Niemand verschickt ungefragt Mails, nur weil er aktualisiert hat.
report_mails haelt fest, was an wen herausgegangen ist. Ohne dieses Protokoll
wuerde ein Neustart oder ein zweiter Anlauf nach einem Teilfehler dieselbe Mail
erneut zustellen. Schlaegt ein Empfaenger fehl, laufen die uebrigen weiter und
der fehlgeschlagene wird beim naechsten Takt erneut versucht, weil er eben noch
nicht protokolliert ist.
Lief der Server am Ersten nicht, wird spaeter im Monat nachgeholt statt den
Bericht ausfallen zu lassen. Wer den Versand neu einschaltet, bekommt deshalb
einmalig den Bericht des Vormonats.
Die Sprache der Mails steht in der Konfiguration. Die Oberflaechensprache haengt
am Browser und steht bei einem Versand ohne Besucher nicht zur Verfuegung.
lettre mit rustls und mitgelieferten Wurzelzertifikaten, kein OpenSSL auf dem
Build-Rechner und keine Systemabhaengigkeit im Ergebnis.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer im Admin-Bereich ein Passwort vergibt, kann jetzt ankreuzen, dass der
Benutzer es beim naechsten Mal selbst aendern muss. Der Haken ist beim Setzen
eines Passworts auf der Benutzerseite vorausgewaehlt, weil ein vom Admin
vergebenes Passwort ueber einen zweiten Kanal weitergegeben wird und damit
nicht mehr nur dem Benutzer bekannt ist. Beim Anlegen eines Kontos ist er
freiwillig und wirkt nur, wenn ueberhaupt ein Passwort gesetzt wird.
Die Durchsetzung sitzt als Middleware vor dem Router, nicht in den einzelnen
Handlern. Solange der Wechsel aussteht, fuehrt jeder Weg auf /password. Frei
bleiben Login, Logout, Sprachwahl, statische Dateien und die OCPP-Endpunkte:
an letzteren haengt keine Sitzung, und ein blockierter Ladepunkt waere ein
uebler Nebeneffekt einer Passwortregel.
Unabhaengig davon kann jeder Benutzer sein Passwort selbst aendern, verlinkt
auf seiner eigenen Seite. Dabei wird das bisherige Passwort abgefragt, das
neue muss mindestens sechs Zeichen haben, zweimal gleich eingegeben werden und
sich vom bisherigen unterscheiden.
Migration 0004 ergaenzt users.must_change_password und legt report_mails an,
die Tabelle fuer den Monatsversand im naechsten Schritt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
In der Liste der eigenen Ladungen stand bei der gerade laufenden Ladung eine
Null. Grund: stop_meter_wh ist NULL, solange geladen wird, und der Code machte
daraus mit unwrap_or(0) eine Null statt den aktuellen Zaehlerstand zu holen.
Die Uebersicht unter /transactions macht das laengst richtig, die eigene Seite
und die Benutzer-Detailseite nicht.
recent_transactions greift fuer laufende Ladungen jetzt genauso auf
live_meter zu. Liegt noch keine Messung vor, steht dort ein Strich statt einer
falschen Null.
Beim Anfassen derselben Zelle ist ein zweiter Fehler aufgefallen: energy_wh /
1000 ist Ganzzahldivision, eine Ladung mit 2,7 kWh stand als "2" da. Die Zelle
formatiert jetzt mit fmt_kwh auf eine Nachkommastelle, wie im Rest der
Anwendung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Themen, die sich fast ueberall beruehren, plus die Umbenennung und die
neue Projektseite.
Mitarbeiter sind Benutzer
Migration 0002 hatte `users` (Login) und `employees` (Person) getrennt. Die
Verknuepfung wurde nur fuer Altdaten einmalig gesetzt und danach nie gepflegt,
weshalb ein Nicht-Admin-Login praktisch nie eigene Ladungen sah. Migration 0003
loest `employees` auf: ein Mitarbeiter ist ein `users`-Eintrag mit
`role='user'`, Chips und Transaktionen haengen wieder an `user_id`. Mitarbeiter
ohne Login bekommen ein Konto ohne Passwort.
Ein Mitarbeiter sieht und steuert ausschliesslich die Ladungen seiner eigenen
Chips. Cockpit, Wallboxen, Chips und Benutzerverwaltung sind serverseitig
admin-only, `/` leitet Nicht-Admins auf `/me`. Der letzte aktive Admin laesst
sich nicht mehr degradieren, deaktivieren oder loeschen.
Ladelimits
Timer und Ziel-kWh je Ladung, Abschaltung beim zuerst erreichten Wert. Ein
Watchdog prueft alle 15 s und schickt RemoteStopTransaction; das Energielimit
wird zusaetzlich sofort nach eingehenden MeterValues geprueft. Lehnt die
Wallbox ab, wird beim naechsten Takt erneut versucht. Vorgaben je Person setzt
der Mitarbeiter selbst oder der Admin.
Chip-Kategorie abgeleitet
Chip mit Benutzer ist ein Mitarbeiter-Chip, ohne ein Gast-Chip. Vorher liessen
sich Zuordnung und Kategorie widersprechen. Die Migration loest dabei die
Pseudo-Person "Gast" auf, mit der der fehlende Begriff nachgebaut wurde.
Umbenennung easy-occp auf easy-ocpp
Im Produktnamen steckte ein Dreher, das Protokoll heisst OCPP. Betrifft Binary,
Cookie, Doku und Release-Workflow. Bestehende Installationen verlieren nichts:
existiert nur die alte data/easy-occp.db, wird sie weiterverwendet.
Dazu
Projektseite in vier Sprachen unter docs/ mit hreflang, Canonical, Open Graph,
JSON-LD und Sitemap. READMEs auf die im Feld gebraeuchlichen Begriffe
ausgerichtet (CSMS, OCPP-Server, self-hosted). Version 0.4.0. Gedankenstriche
aus Code, Doku und UI-Texten entfernt; migrations/0001 und 0002 blieben dabei
unangetastet, weil sqlx eine Pruefsumme ueber den Dateiinhalt bildet.
Bestehende Installationen brachen beim Start mit dem Windows-Release-Binary
ab: "migration 1 was previously applied but has been modified" – obwohl die
Migration inhaltlich seit v0.2.0 unverändert ist.
Ursache: .gitattributes enthielt nur "* text=auto". Zusammen mit
core.autocrlf=true (Standard auf windows-latest-Runnern) checkt
actions/checkout die .sql-Dateien als CRLF aus. sqlx::migrate! bettet den
Dateiinhalt zur Compile-Zeit ein und bildet darüber eine SHA-384-Summe, die
beim Start gegen _sqlx_migrations geprüft wird:
0001_initial.sql mit LF -> 0651a39f...
0001_initial.sql mit CRLF -> 90093a9a...
Die GitHub-Windows-Builds v0.2.0 und v0.3.0 tragen die CRLF-Variante, lokal
gebaute Exes und der Linux-Build die LF-Variante. Datenbanken, die mit einem
LF-Binary angelegt wurden, kollidieren daher mit dem Windows-Release-ZIP.
Zwei Änderungen:
1. .gitattributes erzwingt "*.sql text eol=lf". Ab jetzt erzeugen Windows-
und Linux-Runner identische Prüfsummen.
2. db::repair_line_ending_checksums() hebt eine gespeicherte Prüfsumme vor
dem Migrationslauf an – aber nur, wenn sie exakt der Zeilenenden-Variante
desselben SQL entspricht, in beide Richtungen. Ohne diesen Schritt würde
Punkt 1 jede Installation brechen, die mit dem CRLF-Binary aus dem
GitHub-ZIP von v0.2.0/v0.3.0 angelegt wurde. Echte inhaltliche
Abweichungen führen weiterhin zum Abbruch durch sqlx.
sha2 wird dafür direkte Dependency (war bereits transitiv gelockt, die
Auflösung ändert sich nicht).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Das Feld wurde nie gelesen (das Template arbeitet mit is_assigned_to);
damit entfaellt auch der LEFT JOIN in der Chip-Liste. Build ist jetzt
warnungsfrei.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Web-UI komplett viersprachig: zentrale Übersetzungstabelle (src/i18n.rs,
~200 Keys), Spracherkennung via lang-Cookie und Accept-Language mit
Umschalter in der Topbar (Fallback Englisch). Übersetzt sind alle
Templates, Fehlermeldungen, CSV-Export und der PDF-Monatsbericht
(inkl. Monatsnamen und sprachspezifischem Datumsformat).
Doku viersprachig: README.md jetzt Englisch mit README.de/fr/es.md,
Installations-Guide als ANLEITUNG.md (DE) + INSTALL(.fr/.es).md;
alle Sprachversionen landen im Release-Paket.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Erstveröffentlichung: OCPP 1.6J Central System mit Web-UI (axum, askama,
htmx, SQLite). Chip-/Mitarbeiterverwaltung, Remote-Start/Stop, Statistik,
Live-Anzeige von kWh/Leistung/SoC während der Ladung inkl. automatischer
MeterValues-Konfiguration der Wallboxen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>