Zum Hauptinhalt springen

Uni-Verein 1.10.0 – Einnahmen, EÜR-Export, Zwei-Faktor-Authentifizierung und Demo-Modus 💶🔐

· 8 Minuten Lesezeit
René Herrmann
Senior developer

Veröffentlicht am 30. Oktober 2026

Uni-Verein 1.10.0 macht aus der Beitragsverwaltung eine vollständige Einnahmenverwaltung mit Quittungen, stabilen Belegnummern und Zahlungsdatum. Die neue Finanzauswertung vergleicht Einnahmen und Ausgaben und erzeugt auf Knopfdruck den EÜR-Export für die Steuer. Dazu kommen die Zwei-Faktor-Authentifizierung, ein Demo-Modus und eine ganze Reihe von Sicherheitsverbesserungen. Beim Update gibt es einiges zu beachten, siehe die Hinweise unten.

Highlights​

  • 💶 Einnahmen (UV-65): Die Seite "Beiträge" ist jetzt die Seite "Einnahmen". Neben den Mitgliedsbeiträgen gibt es frei konfigurierbare Einnahmekategorien wie Spenden oder Sponsoring, auch ohne Bankverbindung
  • 🧾 Quittungen (UV-65): Für jeden bezahlten Beitrag und jede bezahlte Einnahme lässt sich eine Quittung als PDF mit fortlaufender Nummer erzeugen
  • 📑 EÜR-Export (UV-65): Die Einnahmen-Überschuss-Rechnung als Excel-Datei mit steuerlichen Prüfungen, Journal und Beitragsnachweis. Dafür braucht es ein Mitglied mit der Aufgabe "Finanzvorstand"
  • 🔢 Stabile Belegnummern (UV-68): E-JJJJ-NNNN für Einnahmen, A-JJJJ-NNNN für Belege, dazu ein explizites Zahlungsdatum
  • 📊 Finanzauswertung (UV-60): Einnahmen und Ausgaben im Vergleich, ersetzt die Belegauswertung
  • 🔐 Zwei-Faktor-Authentifizierung (UV-67): Anmeldung mit Code aus einer Authenticator-App und Wiederherstellungscodes
  • 🎬 Demo-Modus (UV-66): Eine Demo-Instanz mit Beispieldaten, die sich jede Nacht zurücksetzt
  • 🛡️ Härtung (UV-29, UV-64): Anmelde-Token im httpOnly-Cookie, Mail-Verschlüsselung erzwungen, abgesicherte Backup-Wiederherstellung und mehr

Neue Funktionen​

  • 💶 Einnahmen (UV-65): Der Reiter "Mitgliedsbeiträge" zeigt die SEPA-Beiträge, jeder weitere Reiter ist eine konfigurierbare Einnahmekategorie (unter "Einnahmekategorien verwalten", z. B. "Spenden"). Admins und Finanzverwalter können Einnahmen erfassen, bearbeiten, als bezahlt markieren und löschen, Admins stellen gelöschte wieder her. Kennzahlen und ein Zeitraumfilter (Standard: aktuelles Jahr) sind neu. Bezahlte Beiträge werden nicht mehr nach 14 Tagen automatisch gelöscht, bereits so entfernte Beiträge stellt die Migration wieder her
  • 🧾 Quittungen (UV-65): Ein PDF mit fortlaufender Quittungsnummer (JJJJ-NNNN) für jeden bezahlten Beitrag und jede bezahlte Einnahme. Sie wird so aufbewahrt, wie sie ausgestellt wurde, danach lässt sich die Zahlung nicht mehr ändern. Die Quittung ist keine Zuwendungsbestätigung nach § 10b EStG
  • 📑 EÜR-Export (UV-65): Der EÜR-Export steht für Admins und Finanzverwalter auf der Seite "Finanzauswertung" bereit, für alle Jahre ab 2020. Die Excel-Datei enthält die Blätter "EÜR", "Stammdaten", "Journal", "Beitragsnachweis" und "Hinweise". Die steuerlichen Prüfungen nutzen die Grenzen des exportierten Jahres (45.000 € bis 2025, 50.000 € / 50.000 € / 100.000 € ab 2026). Anfangsbestände und der Abgleich Kasse/Bank sind leere Zellen zum Ausfüllen von Hand. Damit der Kassenwart in der EÜR erscheint, muss es ein Mitglied mit der Aufgabe "Finanzvorstand" geben, siehe die Voraussetzungen
  • 🏷️ Steuerlicher Bereich (UV-65): Einnahme- und Belegkategorien haben einen Steuerlichen Bereich (Ideeller Bereich, Vermögensverwaltung, Zweckbetrieb, Wirtschaftlicher Geschäftsbetrieb), die Bankverbindung eine optionale "Steuernummer"
  • 🔢 Belegnummern und Zahlungsdatum (UV-68): Beim Buchen als bezahlt erhält jeder Eintrag einmalig eine Belegnummer, E-JJJJ-NNNN für Beiträge und Einnahmen, A-JJJJ-NNNN für Belege, die sich nie ändert und nie neu vergeben wird. Das Zahlungsdatum (Standard: heute) bestimmt EÜR, Finanzauswertung und Einnahmen-Summen. Bereits bezahlte Einträge behalten ihr bisheriges Datum, frühere Zahlen ändern sich nicht
  • 📊 Finanzauswertung (UV-60): Die Finanzauswertung ersetzt die Belegauswertung und vergleicht Einnahmen und Ausgaben (Übersicht, nach Monat und Kategorie, Kategorientabelle). Es zählen nur bezahlte Einträge, jeweils im Monat ihres Zahlungsdatums, sodass der Saldo zur EÜR passt. Offene Belege erscheinen nicht mehr in den Ausgaben, bis sie bezahlt sind. Nur Admins und Finanzverwalter können sie öffnen
  • 🔐 Zwei-Faktor-Authentifizierung (UV-67): Unter "Profileinstellungen" → "Sicherheit" richtet jeder Benutzer eine 2FA (TOTP) mit QR-Code und 10 Wiederherstellungscodes ein. Bei aktiver 2FA folgt auf das Passwort die Code-Abfrage, falsche Codes werden pro Adresse und pro Konto gesperrt (Wiederherstellungscodes funktionieren währenddessen weiter). Admins können die 2FA eines Benutzers zurücksetzen. Das Geheimnis wird verschlüsselt gespeichert, optional lässt sich der Name in der App mit TwoFactor__Issuer festlegen. Im Demo-Modus nicht verfügbar. Wer als einziger Admin Gerät und Wiederherstellungscodes verliert, hat keinen Weg zurück
  • 🔒 Sitzungen (UV-67): Abmelden, Passwort ändern und das Ändern der 2FA beenden die Sitzungen auf allen anderen Geräten
  • 🎬 Demo-Modus (UV-66): docker-compose-demo.yml baut nichts selbst und braucht keinen SQL-Dump. VERSION in der .env wählt die veröffentlichten Images, DEMO_DATA_PATH den Datenordner. Mit Demo__Enabled=true löscht das Backend bei jedem Start und nachts um 03:00 Uhr UTC Datenbank und Belegdateien und erzeugt Beispieldaten relativ zum aktuellen Datum. E-Mails fängt Mailpit unter /mail/ ab. GET /web-page-config liefert demo, sodass das veröffentlichte Frontend-Image den Demo-Hinweis ohne eigenen Build zeigt
  • 👥 Finanzverwalter mit mehr Rechten (UV-70): Finanzverwalter öffnen die Beitragstarifverwaltung sowie die Einnahme- und Belegkategorien (das Menü "Einstellungen" zeigt ihnen nur diese drei Einträge) und legen Beitragstarife und Kategorien wie Admins an, bearbeiten und löschen sie

Änderungen​

  • 🍪 Anmelde-Token im Cookie (UV-29): Das Token liegt in einem httpOnly-Cookie (uv_auth) statt im localStorage, sodass eingeschleuste Skripte es nicht mehr auslesen können. Datenändernde Cookie-Anfragen tragen den Header X-UV-CSRF, Authorization: Bearer funktioniert weiter. Neu sind GET /auth/me und POST /auth/logout. ?access_token= wird bei /backup, /receipts/export und /emailProgress nicht mehr akzeptiert
  • 📧 Mail-Verschlüsselung (UV-64): Bei aktiviertem SSL wird eine verschlüsselte Verbindung erzwungen (TLS auf Port 465/993, sonst STARTTLS). Vorher konnte das Mailbox-Passwort im Klartext gesendet werden, wenn STARTTLS fehlte. Die Test-Mail meldet, warum etwas fehlgeschlagen ist
  • 🔌 API-Änderungen: GET /receipts/analytics wird durch GET /finance/analytics ersetzt. POST /contributions/{id} und POST /income/{id} erwarten { "paid", "paymentDate" } im Body statt des Query-Parameters paid, POST /receipts/{id}/pay und POST /income akzeptieren ein optionales paymentDate

Fehlerbehebungen und Sicherheit​

  • 🛡️ Backup-Wiederherstellung (UV-64): Eine hochgeladene SQL-Datei kann keine Shell-Befehle mehr im Backend-Container ausführen (psql läuft im eingeschränkten Modus, nötig ist PostgreSQL 17.6 oder neuer, sonst wird die Wiederherstellung abgelehnt)
  • 🎬 Demo-Modus auf dem Server (UV-64): Backup-Download und -Wiederherstellung antworten im Demo-Modus mit 403 DEMO_MODE_DISABLED. Vorher existierte der Demo-Modus nur im Frontend
  • ⚠️ Demo-Löschung (UV-65): Die Löschung der Datenbank braucht ein ausdrückliches Demo__Enabled mit true, 1, yes oder on. Vorher hätte jeder andere Wert (z. B. disabled) eine Produktivdatenbank gelöscht
  • 📝 Selbstregistrierung (UV-64): Alle Textfelder haben eine Maximallänge, POST /self-enrollment lehnt Bodys über 32 KB ab. Anfragen über einem Größenlimit (auch Beleg-Uploads) werden mit 413 statt 500 beantwortet
  • 💶 Beträge (UV-64): Beleg- und Einnahmebeträge sind auf 1.000.000 begrenzt. Vorher ließ sich die Finanzauswertung mit Belegen nahe dem Maximalwert nicht mehr laden (HTTP 500). Bereits gespeicherte höhere Beträge bleiben unverändert
  • 📄 CSV-Exporte (UV-64): Belege-ZIP und Mitgliederexport entschärfen Tabellenformeln (Felder, die mit =, +, - oder @ beginnen)
  • 🖼️ PDF-Vorschau (UV-64): Seiten werden in begrenzter Größe gerendert, ein PDF mit riesiger Seite kann den Browser nicht mehr überlasten. Eine nicht darstellbare Kachel zeigt einen Platzhalter mit dem Link zum Original
  • 🔑 Mail-Einstellungen (UV-64): Das SMTP-/IMAP-Passwort muss bei jedem Speichern neu eingegeben werden, damit das gespeicherte Passwort nicht auf einen anderen Mail-Server umgeleitet werden kann
  • 📊 Einnahmen-Summen (UV-65): Bezahlte Beträge werden nach Zahlungsdatum dem Zeitraum zugeordnet, bezahlte Einnahmen ohne Kategorie fehlen nicht mehr
  • 🗑️ Gelöschte Beiträge (UV-65): Ein gelöschter Beitrag lässt sich nicht mehr als bezahlt markieren

⚠️ Hinweise zum Update​

  • Immer mit docker-compose-update.yml aktualisieren, wie in der README beschrieben. Die nginx.conf muss zusammen mit den Images aktualisiert werden (X-Forwarded-Proto), das erledigt das Update-Skript
  • Alle Benutzer müssen sich nach dem Update einmal neu anmelden (neue Spalte Users.session_version und Wechsel auf das Cookie)
  • Steuerliche Bereiche zuordnen: Die Migration setzt alle vorhandenen Einnahme- und Belegkategorien auf "Ideeller Bereich". Weise die Bereiche zu, bevor du die erste EÜR exportierst, siehe Steuerliche Bereiche zuordnen
  • Für die EÜR: Lege ein Mitglied mit der Aufgabe "Finanzvorstand" an, damit der Kassenwart in der Datei erscheint
  • API-Clients: Der Token muss als Authorization: Bearer gesendet werden (?access_token= entfällt), POST /contributions/{id} und POST /income/{id} brauchen den Body { "paid", "paymentDate" }
  • Mail-Server ohne Verschlüsselung funktionieren mit aktiviertem SSL nicht mehr
  • Offene Belege erscheinen in der Finanzauswertung erst, wenn sie bezahlt sind
  • Bezahlte Beiträge, die bisher nach 14 Tagen automatisch gelöscht wurden, stellt die Migration wieder her. Künftig bleiben bezahlte Beiträge dauerhaft erhalten

Warum diese Updates wichtig sind​

Mit den Einnahmen, den stabilen Belegnummern und dem Zahlungsdatum führt Uni-Verein die Vereinskasse nachvollziehbar: Jede Zahlung hat eine feste Nummer und ein Datum, Spenden lassen sich per Quittung belegen, und die EÜR für das Finanzamt entsteht aus denselben Daten wie die Auswertung. Die Zwei-Faktor-Authentifizierung schützt Konten mit Zugriff auf Mitglieder- und Bankdaten, und die Härtung von Token, Mail-Verschlüsselung und Backup-Wiederherstellung schließt mehrere Angriffswege.

Wie geht es weiter?​

Weiteres Feedback aus der Praxis ist wie immer herzlich willkommen, gerne über GitHub Issues. Schaut auch weiterhin gerne hier vorbei!