Skip to main content

Uni-Verein 1.10.0 โ€“ Income, EรœR Export, Two-Factor Authentication and Demo Mode ๐Ÿ’ถ๐Ÿ”

ยท 9 min read
Renรฉ Herrmann
Senior developer

Published on October 30, 2026

Uni-Verein 1.10.0 turns the contribution management into a complete income management with acknowledgements, stable booking numbers and payment date. The new financial analysis compares income and expenses and creates the EรœR export for tax purposes at the push of a button. On top come two-factor authentication, a demo mode and a whole series of security improvements. There are several things to note when updating, see the notes below.

Highlightsโ€‹

  • ๐Ÿ’ถ Income (UV-65): The "Contributions" page is now the "Income" page. Besides membership fees there are freely configurable income categories such as donations or sponsoring, also without a bank connection
  • ๐Ÿงพ Acknowledgements (UV-65): For every paid fee and every paid income an acknowledgement can be created as a PDF with a consecutive number
  • ๐Ÿ“‘ EรœR export (UV-65): The income and expense statement as an Excel file with tax checks, journal and fee proof. It needs a member with the task "Chief finance officer"
  • ๐Ÿ”ข Stable booking numbers (UV-68): E-YYYY-NNNN for income, A-YYYY-NNNN for receipts, plus an explicit payment date
  • ๐Ÿ“Š Financial analysis (UV-60): Income and expenses compared, replaces the receipt analytics
  • ๐Ÿ” Two-factor authentication (UV-67): Login with a code from an authenticator app and recovery codes
  • ๐ŸŽฌ Demo mode (UV-66): A demo instance with sample data that resets itself every night
  • ๐Ÿ›ก๏ธ Hardening (UV-29, UV-64): Login token in an httpOnly cookie, mail encryption enforced, secured backup restore and more

New Featuresโ€‹

  • ๐Ÿ’ถ Income (UV-65): The "Membership fees" tab shows the SEPA fees, every further tab is a configurable income category (under "Manage income categories", e.g. "Donations"). Admins and Finance Managers can record, edit, mark as paid and delete income, Admins restore deleted entries. Key figures and a period filter (default: current year) are new. Paid fees are no longer deleted automatically after 14 days, the migration restores fees that were already removed this way
  • ๐Ÿงพ Acknowledgements (UV-65): A PDF with a consecutive acknowledgement number (YYYY-NNNN) for every paid fee and every paid income. It is kept exactly as issued, afterwards the payment can no longer be changed. The acknowledgement is not a donation receipt under ยง 10b EStG
  • ๐Ÿ“‘ EรœR export (UV-65): The EรœR export is available for Admins and Finance Managers on the "Financial analysis" page, for all years from 2020. The Excel file contains the sheets "EรœR", "Stammdaten", "Journal", "Beitragsnachweis" and "Hinweise". The tax checks use the limits of the exported year (โ‚ฌ45,000 until 2025, โ‚ฌ50,000 / โ‚ฌ50,000 / โ‚ฌ100,000 from 2026). Opening balances and the cash/bank reconciliation are empty cells to fill in by hand. For the treasurer to appear in the EรœR, there has to be a member with the task "Chief finance officer", see the prerequisites
  • ๐Ÿท๏ธ Tax area (UV-65): Income and receipt categories have a tax area (non-profit sphere, asset management, purpose-related operation, commercial operation), the bank details an optional "Tax number"
  • ๐Ÿ”ข Booking numbers and payment date (UV-68): When booked as paid, every entry receives a booking number once, E-YYYY-NNNN for fees and income, A-YYYY-NNNN for receipts, which never changes and is never reused. The payment date (default: today) determines EรœR, financial analysis and income totals. Entries that are already paid keep their previous date, earlier figures do not change
  • ๐Ÿ“Š Financial analysis (UV-60): The financial analysis replaces the receipt analytics and compares income and expenses (overview, by month and category, category table). Only paid entries count, each in the month of its payment date, so the balance matches the EรœR. Open receipts no longer appear in the expenses until they are paid. Only Admins and Finance Managers can open it
  • ๐Ÿ” Two-factor authentication (UV-67): Under "Profile settings" โ†’ "Security" every user sets up 2FA (TOTP) with a QR code and 10 recovery codes. With 2FA enabled the code prompt follows the password, wrong codes are blocked per address and per account (recovery codes keep working meanwhile). Admins can reset the 2FA of a user. The secret is stored encrypted, optionally the name in the app can be set with TwoFactor__Issuer. Not available in demo mode. If the only Admin loses device and recovery codes, there is no way back
  • ๐Ÿ”’ Sessions (UV-67): Logging out, changing the password and changing the 2FA end the sessions on all other devices
  • ๐ŸŽฌ Demo mode (UV-66): docker-compose-demo.yml builds nothing itself and needs no SQL dump. VERSION in the .env selects the published images, DEMO_DATA_PATH the data folder. With Demo__Enabled=true the backend wipes database and receipt files at every start and at 03:00 UTC every night and generates sample data relative to the current date. Mailpit catches e-mails at /mail/. GET /web-page-config returns demo, so the published frontend image shows the demo hint without its own build
  • ๐Ÿ‘ฅ Finance Managers with more rights (UV-70): Finance Managers open the contribution plan administration and the income and receipt categories (the "Settings" menu shows them only these three entries) and create, edit and delete contribution plans and categories like Admins

Changesโ€‹

  • ๐Ÿช Login token in a cookie (UV-29): The token lives in an httpOnly cookie (uv_auth) instead of localStorage, so injected scripts can no longer read it. Cookie requests that change data carry the header X-UV-CSRF, Authorization: Bearer keeps working. GET /auth/me and POST /auth/logout are new. ?access_token= is no longer accepted on /backup, /receipts/export and /emailProgress
  • ๐Ÿ“ง Mail encryption (UV-64): With SSL enabled, an encrypted connection is enforced (TLS on ports 465/993, otherwise STARTTLS). Before, the mailbox password could be sent in cleartext when STARTTLS was missing. The test mail reports why something failed
  • ๐Ÿ”Œ API changes: GET /receipts/analytics is replaced by GET /finance/analytics. POST /contributions/{id} and POST /income/{id} expect { "paid", "paymentDate" } in the body instead of the query parameter paid, POST /receipts/{id}/pay and POST /income accept an optional paymentDate

Fixes and Securityโ€‹

  • ๐Ÿ›ก๏ธ Backup restore (UV-64): An uploaded SQL file can no longer run shell commands in the backend container (psql runs in restricted mode, PostgreSQL 17.6 or later is required, otherwise the restore is refused)
  • ๐ŸŽฌ Demo mode on the server (UV-64): Backup download and restore answer 403 DEMO_MODE_DISABLED in demo mode. Before, the demo mode only existed in the frontend
  • โš ๏ธ Demo wipe (UV-65): Wiping the database needs an explicit Demo__Enabled of true, 1, yes or on. Before, any other value (e.g. disabled) would have wiped a production database
  • ๐Ÿ“ Self-enrollment (UV-64): All text fields have a maximum length, POST /self-enrollment rejects bodies above 32 KB. Requests above a size limit (also receipt uploads) are answered with 413 instead of 500
  • ๐Ÿ’ถ Amounts (UV-64): Receipt and income amounts are limited to 1,000,000. Before, the finance analytics could no longer be loaded with receipts near the maximum value (HTTP 500). Amounts already stored above the limit are not changed
  • ๐Ÿ“„ CSV exports (UV-64): The receipts ZIP and the member export neutralise spreadsheet formulas (fields starting with =, +, - or @)
  • ๐Ÿ–ผ๏ธ PDF preview (UV-64): Pages are rendered at a limited size, so a PDF with a huge page can no longer exhaust the browser. A tile that cannot be rendered shows a placeholder with the link to the original
  • ๐Ÿ”‘ Mail settings (UV-64): The SMTP/IMAP password must be entered again on every save, so the stored password cannot be redirected to another mail host
  • ๐Ÿ“Š Income totals (UV-65): Paid amounts are assigned to the period by payment date, paid income without a category is no longer left out
  • ๐Ÿ—‘๏ธ Deleted fees (UV-65): A deleted fee can no longer be marked as paid

โš ๏ธ Update Notesโ€‹

  • Always update with docker-compose-update.yml, as described in the README. The nginx.conf has to be updated together with the images (X-Forwarded-Proto), the update script takes care of that
  • All users have to log in once again after the update (new column Users.session_version and the switch to the cookie)
  • Assign tax areas: The migration sets all existing income and receipt categories to "Non-profit sphere". Assign the areas before you export the first EรœR, see Assign tax areas
  • For the EรœR: Create a member with the task "Chief finance officer" so the treasurer appears in the file
  • API clients: The token has to be sent as Authorization: Bearer (?access_token= is gone), POST /contributions/{id} and POST /income/{id} need the body { "paid", "paymentDate" }
  • Mail servers without encryption no longer work with SSL enabled
  • Open receipts appear in the financial analysis only once they are paid
  • Paid fees that used to be deleted automatically after 14 days are restored by the migration. In future paid fees are kept permanently

Why These Updates Matterโ€‹

With income, stable booking numbers and the payment date, Uni-Verein keeps the club's cash traceable: every payment has a fixed number and a date, donations can be documented with an acknowledgement, and the EรœR for the tax office is created from the same data as the analysis. Two-factor authentication protects accounts with access to member and bank data, and the hardening of tokens, mail encryption and backup restore closes several attack paths.

What's Next?โ€‹

Further feedback from practice is as always very welcome, feel free to use GitHub Issues. Keep checking back here!