Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

Alle nennenswerten Änderungen an Parkrr, aus Sicht der Menschen, die es bedienen
und betreiben. Format angelehnt an [Keep a Changelog](https://keepachangelog.com/de/);
das Projekt lebt auf `dev` und wird über Pull Requests nach `main` (= Produktion)
gebracht — „Unreleased" ist, was auf `dev` liegt und den nächsten Deploy bildet.

Pflege-Regel: Jeder Batch/PR, der Verhalten ändert, trägt hier eine Zeile ein —
in der Sprache der Anwender („Rechnungen lassen sich als CSV exportieren"), nicht
der Implementierung („neue Spalte in export.go").

## [Unreleased]

### Review-Nachbesserungen · Oktober 2026

- Bestehende Buchungspreise bleiben bei Tarifänderungen erhalten; noch dynamisch
  tarifabhängige Altbuchungen lösen einen verständlichen Konflikt aus.
- Bereits erfasste Pauschalen-/Nebenkostenzahlungen werden bei Reset, Ersetzung
  oder Quellenlöschung nicht mehr gelöscht. Vorläufiger Konfliktschutz bis zum
  geprüften Storno-/Neubuchungsablauf; neue einzelne Zahlungen bleiben möglich.
- Steuer-ZIP einschließlich Belegen aus einem gemeinsamen lesenden Snapshot;
  begrenzter temporärer Belegspeicher statt offener DB-Verbindung beim Download.
- Optionaler, standardmäßig nur lesender Steuerbereich und nicht speichernde
  Vorschau für Jahresumsätze und einzelne Jahreswechsel-Fälle (2025/2026).
  Keine Pflicht zur Rechnungserstellung; kein automatischer Jahreskorrekturimport.

Stand des Verbesserungsprogramms „Parkrr-Hundert" (September 2026).

### Hinzugefügt
- **Vollständiges Steuerjahr für Vermietung und Verpachtung:** Einnahmen nach
  Zuflussdatum, korrigierbare Schalter-Daten, Steuerobjekte über den Hallen,
  unveränderliche Werbungskosten samt Belegen und Storno, wiederkehrende
  Ausgaben, Anlagenverzeichnis mit linearer AfA/Halbjahresregel sowie
  Überschuss und E1b-Vorschau je Objekt. Dazu kommen 15-Tage-Regel,
  Kleinunternehmer-Fortschritt, Jahresabschluss-Sperre und ein ZIP-Paket mit
  PDF, CSV-Dateien und sämtlichen Belegen für den Steuerberater.
- **Konto sperren statt löschen:** Benutzerkonten können deaktiviert werden;
  die Sperre wirkt sofort (auch auf laufende Sitzungen) und erhält die
  Urheberschaft auf Rechnungen, Zahlungen und Übergabeprotokollen.
- **Mahnwesen mit Stufen:** Zahlungserinnerung → 1. Mahnung → 2./letzte Mahnung,
  mit Gedächtnis („2× gemahnt, zuletzt …") an der Rechnung.
- **Offene-Posten-Liste als PDF** mit Stichtag, neben den CSV-Exporten.
- **CSV-Export für Rechnungen und Zusatzkosten** (Buchhaltung/Steuerberater).
- **Revisionssicherer Audit-Export:** JSONL mit SHA-256-Hashkette, prüfbar ohne
  Parkrr (Audit-Seite → „Revisionsexport").
- **Alarm bei Backup-Fehlschlag** per E-Mail (`PARKRR_ALERT_EMAIL`).
- **Mindest-Aufbewahrung für Backups** in Tagen, zusätzlich zur Anzahl
  (Backup-Reiter) — ein Boden, der Historie schützt.
- **2FA-Pflicht** (`PARKRR_REQUIRE_2FA`) und **Passkey-only-Modus**
  (`PARKRR_PASSKEY_ONLY`) als Betreiber-Schalter, Default aus.
- **Geschäftszeitzone** (`PARKRR_TIMEZONE`): „heute" und „dieser Monat" folgen
  dem Betrieb, nicht der Container-Uhr.
- **Standardmaße je Tarif** für den Garagenplaner: ungemessene Gefährte erben
  eine brauchbare erste Näherung; eigene Maße gewinnen immer.
- **Batch-Speichern im Garagenplaner:** Auto-Anordnen schreibt alle Plätze in
  einer Transaktion — keine halb angeordnete Halle mehr bei einem Abbruch.
- **Automatischer Rechnungslauf** (`PARKRR_AUTO_INVOICE_CRON`, Default aus):
  erstellt Rechnungen nach Zeitplan über denselben Pfad wie der Knopf; schon
  abgerechnete Perioden werden nie doppelt fakturiert.
- **`parkrr seed-demo`:** befüllt eine frische Datenbank mit erkennbaren
  Demo-Daten (idempotent; weigert sich auf einer benutzten Datenbank).
- **Storno-Dokumente nennen die stornierte Rechnungsnummer** (§11 UStG).
- **Portal-Briefkasten:** Kunden können Kontaktdaten-Änderungen und Abholtermine
  einreichen; der Betreiber übernimmt sie per Klick auf der Übersicht — das
  Portal selbst schreibt nie in Stammdaten.
- **Portal auf Englisch:** folgt der Browsersprache, umschaltbar, mit Gedächtnis.
- **Kalenderansicht:** Abholungen, Reservierungen, fällige Rechnungen und
  Abholwünsche im Monatsraster.
- **Bulk-Aktionen:** mehrere Gefährte gemeinsam als abgeholt markieren oder
  stornieren.
- **Datei-Anhänge** (PDF/JPEG/PNG) je Person und Gefährt, mit erzwungenem
  Download und Prüfung am Dateiinhalt.
- **Verlauf je Person** (alle Ereignisse in einem Strom) und
  **Belegungshistorie je Stellplatz** ("wer stand wann auf Platz 3?").
- **Titelbild & Fotoreihenfolge** für Gefährt-Fotos; der Planer zeigt das
  Titelbild.
- **E2E-Tests für Login, 2FA und Passkey** (echter TOTP, virtueller
  WebAuthn-Authenticator).
- **Betreiber-Handbuch** (docs/betreiber-handbuch.md).

### Geändert
- **PDFs (Rechnung, Übergabeprotokoll, Berichte) mit eingebetteter
  Unicode-Schrift:** Kundennamen wie „Łukasz" oder „Nováková" stehen jetzt
  richtig auf den Belegen.
- **DSGVO-Anonymisierung reicht bis zur Unterschrift** im Übergabeprotokoll;
  der Beleg selbst bleibt als Beleg erhalten.
- **Abgeschnittene Listen sagen es:** zeigt der Server nur die ersten 1000
  Einträge, steht das jetzt über der Liste, statt vollständig auszusehen.
- Schnelle Routenwechsel können die neue Seite nicht mehr mit dem Ergebnis der
  alten überschreiben (Render-Wettlauf behoben).
- Formulardialoge behalten bei einem Fehler die Eingaben, statt zu schließen
  (u. a. S3-Wiederherstellung, Recovery-Codes).
- Die Symbol-Knöpfe (✕, 🗑, ⟳, ⭳) sind echte Icons statt Emojis — einheitlich
  auf allen Plattformen und für Screenreader benannt.

### Behoben (Mehr-Augen-Durchsicht des Programms)

Eine Durchsicht über alle 41 Programm-Commits, aus elf unabhängigen Blickwinkeln,
hat die folgenden Fehler gefunden. Jeder wurde am Code nachgeprüft, bevor er
angefasst wurde.

- **Aussperr-Sperre beim Sperren von Konten:** Der Schutz vor „null Admins"
  zählte auch bereits gesperrte Admins mit. Damit ließ sich ein Konto nach dem
  anderen sperren, bis sich niemand mehr anmelden konnte — und das Entsperren
  liegt selbst hinter der Admin-Rolle. Gezählt werden jetzt nur anmeldbare
  Admins; der erzwungene Bootstrap-Lauf
  (`PARKRR_ADMIN_PASSWORD_FORCE`) hebt zusätzlich eine Sperre auf und ist damit
  der dokumentierte Notausgang.
- **Kundenwunsch konnte eine DSGVO-Löschung rückgängig machen:** Ein vor der
  Löschung eingereichter Kontaktdaten-Wunsch schrieb beim „Übernehmen" E-Mail,
  Telefon und Anschrift wieder auf die anonymisierte Person. Wird jetzt
  abgelehnt (ablehnen/erledigen bleibt möglich).
- **Die Löschung erreicht jetzt alle Nebentabellen:** Portal-Wünsche (die
  gewünschte neue Anschrift stand dort im Klartext), Datei-Anhänge, das
  Versandprotokoll und die Stellplatz-Historie (Kennzeichen + Personenbezug)
  blieben unberührt — drei davon hängen an keinem Fremdschlüssel und überlebten
  auch ein echtes Löschen.
- **Passkey-Anmeldung ignorierte die Konto-Sperre:** Ein gesperrtes Konto konnte
  sich per Passkey anmelden und bekam eine neue Sitzung samt „angemeldet"-Eintrag
  im Protokoll.
- **Automatischer Rechnungslauf hielt bei EINEM lückenhaften Datensatz an:** Eine
  fehlende Empfängeranschrift (ab 400 € Pflicht) galt als betriebsweiter Mangel
  und brach den ganzen Lauf ab — alle nachfolgenden Personen blieben unfakturiert,
  Nacht für Nacht, ohne Hinweis in der Zusammenfassung. Verkäufer- und
  Empfängermängel werden jetzt unterschieden; die Zusammenfassung nennt
  übersprungene Personen und einen Abbruch ausdrücklich.
- **Ein Programmfehler im Rechnungslauf konnte den Dienst beenden:** Der Lauf
  umging die Absturzsicherung, die bei jedem normalen Aufruf greift.
- **Planer: Torhöhe und Traglast wurden nach dem Ablegen nicht mehr geprüft.**
  Tarif-Standardmaße galten nur in der Ablageleiste; auf einem Platz meldete
  dasselbe Gefährt keine Maße, und die Warnung blieb still.
- **Planer: Fläche und Raumangaben blieben nach Wandänderungen und Rückgängig
  stehen** (auch im Export) — bis zufällig eine andere Aktion neu rechnete.
- **Ein neu hochgeladenes Foto verdrängte das gewählte Titelbild.**
- **Mehrfachauswahl: der Zähler blieb bei „0 ausgewählt"**, obwohl die Auswahl
  griff — eine Massenaktion ohne prüfbare Zahl.
- **Kalender: die Ebene „Fällige Rechnung" konnte nur Vergangenes zeigen** und war
  in jedem künftigen Monat garantiert leer.
- **Revisionsexport brach bei großem Protokoll still nach zehn Sekunden ab** —
  mit bereits gesendetem Status 200.
- **Widerrufene Portal-Links verschwanden binnen einer Stunde** statt der
  zugesagten 30 Tage; der Betreiber sah nicht mehr, dass je einer bestand.
- **500er-Fehler wurden ohne Ursache protokolliert:** elf Stellen reichten die
  falsche Fehlervariable weiter. Ein Quelltext-Test verhindert den Rückfall.
- **Diagramme: Tastatur-Ansage und Datentabelle kamen bei Screenreadern nie an**
  (beide lagen innerhalb einer als Bild ausgezeichneten Hülle).
- **Escape wirkte nach einem Planer-Dialog sitzungsweit nicht mehr**, wenn der
  Dialog durch einen Seitenwechsel verschwand.
- **Abmelden räumt die Ansichtszustände auf:** der nächste Anmeldende am selben
  Rechner sah sonst die Suchbegriffe und Filter des vorigen.
- **Das Versandprotokoll nennt die tatsächlich angeschriebenen Adressen**, nicht
  die Rohliste (unparsbare werden vom Versand verworfen).
- **Personen-Verlauf zeigte Datumsangaben um einen Tag versetzt**, sobald eine
  Geschäftszeitzone gesetzt ist.
- **Audit-Suche:** `%` und `_` wirkten als Jokerzeichen; eine Ein-Zeichen-Eingabe
  lieferte das gesamte Protokoll als „Treffer".
- **Portal-Briefkasten:** der Deckel gegen Spam ließ sich durch gleichzeitige
  Einreichungen umgehen.
- **„Protokoll löschen"** wurde Bearbeitern angeboten, obwohl nur Admins es
  dürfen (Fehlschlag erst nach dem Rückgängig-Fenster).
- Kleinere Korrekturen: Kunden- und Betreiberansicht nennen denselben Zustand
  jetzt gleich („eingelagert"), das Portal-Wunsch-Protokoll zeigt wieder Werte
  statt „leer → leer", PDF-Schriften werden einmal statt je Dokument geladen, und
  der Portal-Kennzahlenpfad lädt nicht mehr die Abgleichsdaten aller Kunden.

### Behoben (zweite Durchsicht)

- **Der automatische Rechnungslauf überlebt einen Neustart mittendrin:** Der Lauf
  merkte sich „erledigt", bevor er begann. Ein Update, ein Reboot oder ein
  Speicherengpass in genau dieser Minute ließ den Rest des Laufs ersatzlos
  ausfallen — bis zum nächsten Termin, also je nach Zeitplan einen Monat lang,
  ohne Eintrag und ohne Alarm. Der Merker wird jetzt erst nach dem Lauf gesetzt;
  eine Wiederholung kostet nichts, weil abgerechnete Perioden gesperrt bleiben.
- **Ein Lauf, der an der Zeitgrenze abbricht, sagt das jetzt auch:** Bisher las
  sich die Zusammenfassung wie ein geglückter Lauf, während Hunderte Personen
  unfakturiert blieben.
- **Mahnen blockiert die Anwendung nicht mehr:** Der Mahnvorgang belegte während
  der E-Mail-Zustellung eine Datenbankverbindung und forderte für den
  Protokolleintrag noch eine zweite an. Bei mehreren gleichzeitigen Mahnungen und
  einem trägen Mailserver stand die ganze Anwendung. Außerdem geht eine versandte
  Mahnung nicht mehr verloren, wenn der Browser währenddessen geschlossen wird —
  sonst bekam der Kunde dieselbe Stufe ein zweites Mal.
- **Die Mahnstufe auf der Rechnungsseite stimmt nach dem Senden:** Ein zweiter
  Klick fragte weiter nach der „Zahlungserinnerung", während tatsächlich die
  1. Mahnung hinausging.
- **Filter überleben eine Massenaktion:** Status-, Personen- und Archivfilter der
  Gefährteliste wurden bei jedem Neuaufbau der Seite zurückgesetzt — auch direkt
  nach einer Massenaktion, was die fehlgeschlagenen Zeilen wieder aus der Auswahl
  warf. Und ein Tastendruck im Suchfeld löscht die Mehrfachauswahl nicht mehr.
- **Zu große Dateien sagen jetzt, dass sie zu groß sind,** statt „HTTP 413": die
  Größenschranke antwortet im Klartext, und die Anhang-Auswahl prüft schon vor
  dem Hochladen. **Achtung, echte Einschränkung:** die Obergrenze für einen
  Anhang liegt damit bei **8 MB statt bisher 10** — die 10 waren ohnehin nie
  erreichbar, weil der allgemeine Deckel für eine Anfrage darunter lag und ein
  größerer Anhang schon vorher unverständlich abgewiesen wurde. Ein Scan
  zwischen 8 und 10 MB muss künftig verkleinert werden.
- **Widerrufene Portal-Links bleiben als „widerrufen" sichtbar** — das Ausstellen
  eines neuen Links für irgendwen löschte zuvor die widerrufenen Zeilen aller
  Personen.
- **Der Start bricht nicht mehr an Zeilenenden ab:** Die Prüfsumme der
  Migrationen rechnet zeilenenden-unabhängig und hebt eine alt aufgezeichnete
  Summe einmalig an, statt sie bei jedem Start neu zu schreiben.
- **Die Löschung einer Person trifft im Mail-Protokoll genau ihre Adresse.**
  Zuvor wurde als Textmuster gesucht: eine Person mit der Adresse „%@%" — im
  Portal selbst wünschbar — hätte beim Löschen die Empfängerspalte des GANZEN
  Protokolls geleert, und fremde Zeilen mit ähnlicher Adresse wurden mit
  anonymisiert. Umgekehrt bleibt eine Adresse mit Leerraum jetzt nicht mehr
  stehen, während die Person als gelöscht gemeldet wurde.
- **Eine versandte Mahnung, die nicht festgehalten werden kann, wird gemeldet.**
  Bisher meldete die Oberfläche Erfolg, während die Stufe ungezählt blieb — der
  nächste Klick schickte dieselbe Stufe ein zweites Mal. Jetzt sagt die Meldung,
  dass die Mail draußen ist, und warnt ausdrücklich vor dem zweiten Klick.
- **Parkfläche, Raum-m² und Frei/Belegt stimmen nach jeder Planänderung.** Nach
  dem Verschieben an eine Wand oder dem Löschen von Wänden mit dem Auswahlrahmen
  zeigten die Kennzahlen und der SVG-/PDF-Export weiter den vorherigen Stand.
- **Die Neustart-Warnung der Betriebsüberwachung kann erstmals auslösen:** die
  Prozess-Kennzahlen, auf die die mitgelieferte Alarmregel sich stützt, wurden
  bisher gar nicht ausgeliefert — eine stille Lücke, die wie „alles ruhig" aussah.
- **Eine einmalige Wartungsaufgabe kann sich nicht mehr selbst dauerhaft
  blockieren.** Beim Lösen ihrer Sperre wurde bisher nur ein Fehler beachtet, nicht
  aber die Antwort „Sperre gar nicht gehalten"; die Verbindung ging danach samt
  Sperre in den Pool zurück und jeder weitere Anlauf meldete bis zu einer Stunde
  lang „läuft bereits". Dieselbe Behandlung wie beim Mahnen.
- **Die Belegungshistorie kennt jetzt auch die Gefährte, die beim Update schon
  auf einem Platz standen.** Die Historie wird von einer Änderungsüberwachung
  gefüllt; wer im Moment ihrer Einführung bereits stand, hatte nie eine Änderung
  ausgelöst und fehlte deshalb — der Platz galt als frei, und die erste
  Umplatzierung hinterließ keine Vorgeschichte. Übernommen wird „ab hier
  nachweislich belegt": der wahre Beginn wurde nie aufgezeichnet.
- **Die Löschung einer Person erreicht jetzt auch das Mahn-Protokoll.** Die
  Anonymisierung reichte bis ins E-Mail-Protokoll, hörte aber genau davor auf, wo
  die Adresse ein zweites Mal steht: in den versendeten Mahnungen. Sie blieb dort
  dauerhaft lesbar. Stufe und Zeitpunkt bleiben als Nachweis stehen, nur die
  Adresse verschwindet.
- **Das E-Mail-Versandprotokoll sagt jetzt, wenn es mehr Einträge gibt als es
  zeigt.** Angezeigt wurden immer nur die neuesten 200 — ohne Blätterung und ohne
  Hinweis, während das Handbuch „jeder Versuch" verspricht. Wer den ältesten
  Fehlversuch suchte, sah unsichtbar ein Ende.
- **Ein vorübergehend unlesbarer Merker kostet keine Fakturierungsperiode mehr.**
  Der automatische Rechnungslauf las ihn einmal beim Start und übersetzte einen
  Lesefehler in „jetzt" — eine Störung beim Hochfahren (Datenbank noch nicht
  oben) verschob den nächsten Termin damit lautlos um eine ganze Periode. Jetzt
  wird je Takt gelesen; ein Fehler lässt den Takt aus, und sobald die Datenbank
  antwortet, wird die versäumte Periode nachgeholt. Bleibt der Merker eine
  Viertelstunde unlesbar, steht das als Fehler im Protokoll statt als einzelne
  Warnung von vorhin.
- **Eine unter dem laufenden Betrieb zurückgespielte Sicherung startet keinen
  Rechnungslauf mehr.** Der eingespielte, ältere Merker gilt nicht mehr gegen den
  Stand im Speicher. **Unverändert gilt:** in Test- und Kopier-Umgebungen
  `PARKRR_AUTO_INVOICE_CRON` leer lassen.
- **Ein kaputter Upload heißt nicht mehr „zu groß".** Jeder Fehler beim Einlesen
  eines Datei-Uploads — fehlender Rahmen, abgebrochene Übertragung — wurde als
  „Datei ist zu groß" gemeldet, auf allen fünf Upload-Wegen (Anhänge, Fotos,
  CSV-Import, Planer-Symbole). Jetzt sagt nur eine wirklich zu große Datei „zu
  groß"; alles andere bekommt eine zutreffende Meldung.
- **Der CSV-Export ist jetzt durchgehend deutsch formatiert:** USt-Prozent und
  Menge kamen mit Punkt-Dezimalen („20.00"), die ein deutsches Excel nicht als
  Zahl liest — alle übrigen Zahlenspalten hatten längst das Komma.
- **Der Wechsel in den Garagenplaner wird Screenreadern jetzt angesagt.** Jede
  andere Ansicht meldete den Routenwechsel über die Live-Region; der Planer baut
  seine eigene Kopfleiste und blieb stumm.
- **Rücksicherung und Unterschrift nennen jetzt erreichbare Grenzen.** Beide
  versprachen eine Größe, die nie durchging: bei der Rücksicherung lag die eigene
  Grenze exakt auf dem allgemeinen Deckel für eine Anfrage, sodass der Umschlag
  der Übertragung immer darüber lag — die hilfreiche Meldung („dafür bitte die
  Kommandozeile, `parkrr restore`") wurde nie erreicht. Bei der Unterschrift
  scheiterte ein großes Bild am JSON-Leser mit einem Syntaxfehler, statt
  „Signatur zu groß" zu melden. **Achtung, echte Einschränkung:** die
  Rücksicherung über den Browser liegt jetzt bei **8 MB statt nominell 9** —
  größere Sicherungen gehen weiterhin über die Kommandozeile.

### Behoben (Audit 24. 09. 2026)
- **„Bezahlt" deckt keine Zukunft mehr ab:** Ein bezahltes Gefährt und eine
  bezahlte Nebenkosten-Position wurden danach nie wieder abgerechnet. Jetzt gilt
  „bezahlt" nur bis zum Buchungstag bzw. für abgeschlossene Perioden; spätere
  Miete und Nebenkosten erscheinen wieder auf Rechnungen und im Rechnungslauf.
- **Zusatzkosten-Schalter blockiert keine Rechnungen mehr:** Eine Position auf
  einer offenen Rechnung oder mit echter Zahlung lässt sich nicht mehr umschalten
  (Hinweis statt Fehler); der Rechnungslauf meldet solche Konflikte als Fehler.
- **Keine Doppelbuchung bei Wackel-Netz:** „Rechnung bezahlen" und neue
  Zusatzkosten/Nebenkosten werden bei erneutem Speichern nicht doppelt angelegt.
- **Leistungszeitraum** auf Rechnungen endet am letzten tatsächlich abgerechneten
  Tag (nicht mehr am Ausstellungsdatum).
- **Gleichzeitiges Abrechnen und Bezahlen** derselben Periode ist ausgeschlossen;
  Storno und Zahlungsumkehr zur selben Zeit liefern „bitte erneut versuchen"
  statt eines Serverfehlers.
- **Rücksicherung älterer Backups** legt die App nicht mehr lahm: die Datenbank
  wird vollständig durch den Backup-Stand ersetzt.
- **Backups mit mehreren Instanzen:** ein bereits laufendes Backup wird
  übersprungen statt als Fehler gemeldet; Instanzen löschen sich keine
  Zwischendateien mehr.
- **Wiederherstellung wartet nicht mehr** bis zu 30 Minuten auf ein laufendes
  Backup — es wird abgebrochen.
- **Die nächtliche Prüfung schreibt keinen unverschlüsselten Datenbank-Dump mehr.**
- **2FA-Codes lassen sich nicht mehr durchprobieren:** Nach 5 Fehlversuchen
  sperrt der zweite Faktor zunehmend länger (1 Min … 24 h); ein Admin-Reset hebt
  die Sperre auf.
- **Passwortwechsel und Admin-Reset** können sich nicht mehr gegenseitig
  aushebeln; nach einem 2FA-Reset bleibt keine Sitzung eines Angreifers übrig.
- **Übergabeprotokolle und Anhänge** gehören der Person, die sie beim Anlegen
  besaß — nach einem Halterwechsel sieht der neue Halter im Portal nichts mehr
  vom alten; Anonymisieren trifft die richtige Person.
- **Anonymisieren entfernt alle bekannten E-Mail-Adressen** der Person auch aus
  dem Mail-Protokoll; neue Fehlermeldungen enthalten keine Adressen mehr.
- **Audit-Export** großer Protokolle bricht nicht mehr nach 30 s ab.
- **Sitzung abgelaufen:** Speichern führt direkt zur Anmeldung („Sitzung
  abgelaufen") statt in eine Fehlerschleife; der Garagenplaner hört dann auf,
  im Hintergrund zu speichern, und verliert keine Verschiebung mehr.

### Betrieb: Hinweise zum Deploy dieses Stands
- **Migrationen 075–077 laufen beim Start einmalig:**
  - 075: Benutzernamen, die sich nur in Groß-/Kleinschreibung unterscheiden,
    werden umbenannt (`name-dup<ID>`, ältestes Konto behält den Namen; im
    Audit-Log vermerkt). Betroffene melden sich mit dem neuen Namen an.
  - 076: bestehende Übergabeprotokolle und Fahrzeug-Anhänge werden dem
    *aktuellen* Halter zugeordnet. Halterwechsel sind danach gesperrt, sobald
    ein Protokoll oder Anhang existiert.
  - 077: bisher „bezahlte" Gefährte/Nebenkosten gelten bis zur letzten
    abgeschlossenen Periode als bezahlt; alles danach wird wieder fällig. Der
    **erste Rechnungslauf danach kann Monate nachholen**, die bisher still
    übergangen wurden.
- **Backup-Zwischendateien** liegen jetzt unter `<PARKRR_BACKUP_DIR>/.tmp`
  (Default `/backups/.tmp`); dort etwa die doppelte Archivgröße frei halten.
  `PARKRR_BACKUP_DIR` muss auch bei reinem S3-Betrieb auf ein beschreibbares
  Volume zeigen.
- **Volume-Backups** heißen jetzt `parkrr-<Zeitstempel>-<Zufall>.dump.enc`.
- **Alte Backup-Formate** über 64 MiB lassen sich nur noch per `parkrr restore`
  (CLI) wiederherstellen.
- **IPv6-Rate-Limit** gilt pro /64-Netz; nur ein Audit-Export gleichzeitig.

### Entfernt
- Die seit Migration 012 tote Alt-Tabelle `flatrate_paid_years`; noch vorhandene
  historische Zeilen werden beim Update automatisch ins Änderungsprotokoll
  archiviert.

### Betrieb
- Neue optionale Umgebungsvariablen: `PARKRR_ALERT_EMAIL`, `PARKRR_TIMEZONE`,
  `PARKRR_REQUIRE_2FA`, `PARKRR_PASSKEY_ONLY` — alle Default aus/leer, ohne sie
  ändert sich nichts. Details in der README (Configuration).
- Abgelaufene Portal-Links und Passkey-Zeremonien werden jetzt stündlich
  aufgeräumt, nicht mehr nur beiläufig.
- Backups: fehlgeschlagene geplante Läufe können alarmieren (s. o.); die
  Aufbewahrung kann eine Mindest-Historie in Tagen garantieren.