No description
  • Java 51.8%
  • TypeScript 31.1%
  • HTML 14.7%
  • JavaScript 1.5%
  • SCSS 0.7%
  • Other 0.1%
Find a file
Joniras c653f3839f
Some checks are pending
CI / backend (push) Waiting to run
CI / frontend (push) Waiting to run
feat: session cookie
2026-07-21 18:32:00 +02:00
.cursor feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
.github refactor: Enhance documentation and improve authentication handling 2026-07-07 10:46:31 +02:00
.vscode feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
backend feat: session cookie 2026-07-21 18:32:00 +02:00
bank-browser feat: enhance Kassier-Dashboard with bank balance synchronization 2026-07-20 11:11:13 +02:00
docker feat: security enhancements 2026-07-20 20:02:16 +02:00
docs feat: session cookie 2026-07-21 18:32:00 +02:00
frontend feat: session cookie 2026-07-21 18:32:00 +02:00
scripts feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
.agent.md feat: security enhancements 2026-07-20 20:02:16 +02:00
.dockerignore feat: set password via recovery link, edit authentik email 2026-05-26 19:55:43 +02:00
.env.example feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
.gitattributes feat: set password via recovery link, edit authentik email 2026-05-26 19:55:43 +02:00
.gitignore feat: small improvements to usability 2026-06-20 00:10:00 +02:00
AGENTS.md feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
authentik-setup.md feat: Rechnungsprüfer nun vereinfacht (keine authentik rolle mehr) 2026-06-21 08:19:40 +02:00
CHANGELOG.md feat: session cookie 2026-07-21 18:32:00 +02:00
CONTRIBUTING.md refactor: Enhance documentation and improve authentication handling 2026-07-07 10:46:31 +02:00
docker-compose.dev.yml feat: bank browser reload 2026-06-23 21:08:46 +02:00
docker-compose.yml feat: release version 4.0.0 with wallet donation and payout audit features 2026-07-21 00:17:37 +02:00
matrix-setup-dev.md feat: further matrix improvements, verification works, room permission management works not really perfect 2026-06-15 22:32:00 +02:00
README.md feat: session cookie 2026-07-21 18:32:00 +02:00

node-K Management

Web-App für Vereinsverwaltung, Finanzen und Mitglieder-Self-Service — entwickelt für den Verein node-K.

Was die Anwendung kann

Mitglieder & Vorstand

  • Mitgliederverwaltung — Self-Service-Portal, Vorstands- und Admin-Oberfläche
  • Willkommensnachricht — Vorstand bearbeitet den Login-Dialog; Mitglieder können ihn dauerhaft ausblenden
  • Mitgliedstypen — ordentliche, fördernde und Ehrenmitglieder
  • E-Mail an Mitglieder — Vorlagen, Platzhalter, Empfänger-Presets, Anhänge, Hintergrund-Versand, Versandprotokoll mit Empfängerstatus
  • Mitgliedsdokumente — Vorstand lädt Anhänge hoch und steuert die Sichtbarkeit; Mitglieder sehen freigegebene Dokumente im Profil
  • Beitrags-Dauerauftrag — Anleitung für Mitglieder, Bestätigung nach Einrichtung, sichtbar für den Vorstand
  • Externe Benachrichtigungen — Webhooks oder ntfy für Vereinsereignisse
  • DSGVO — Datenexport und Anonymisierung auf Anfrage

Finanzen & Buchhaltung

  • hledger-Buchführung — Buchungen in der Web-UI
  • Git-versionierte Finanzdaten — Journal und Belege im Repository
  • Automatische Beitragsverbuchung — monatlicher Lauf inkl. Dauerauftrag-Bestätigung
  • Bank-Integration (Volksbank) — Kontoumsätze abrufen, abgleichen und zuordnen
  • Buchungsvorlagen, Belege — wiederkehrende Buchungen; PDF/PNG/JPG-Anhänge; Kartenausgaben bei der Buchung verknüpfen
  • Rechnungsprüfung — Transaktionsliste und Belege für Kassier und Rechnungsprüfer

Wallet & Kiosk

  • Mitglieds-Wallet — Guthaben, Aufladung per QR-Code, Auszahlungsanträge
  • Spenden & Terminal-Modus — Kiosk für Aufladungen und Spenden am Standort

Genehmigungen & Sicherheit

  • 4-Augen-Prinzip — Kartenausgaben per Push genehmigen; Verknüpfung mit Buchungen
  • Rollen & Berechtigungen — Mitglied, Vorstand, Kassier, Rechnungsprüfer, IT-Admin
  • Authentik (OIDC) — Login und Gruppen-Sync
  • Audit-Log — nachvollziehbare Protokollierung sicherheitsrelevanter Aktionen; Admin kann alte Einträge bereinigen

Integrationen & App

  • Matrix — Konto verknüpfen, Raumberechtigungen, automatische Mitgliedschafts-Sync
  • Web Push — Browser-Benachrichtigungen für Genehmigungen und Updates
  • PWA — installierbare App mit automatischen Updates und In-App-Changelog

Tech Stack

Backend Java 25, Spring Boot 4.0.6, PostgreSQL, Flyway, JGit
Frontend Angular 21 (zoneless, signals, standalone), Bootstrap 5 dark
Auth authentik (OAuth2/OIDC)
Buchhaltung hledger (CLI)
Deployment Docker multi-stage build

Projektstruktur

backend/                    Spring Boot (Java 25, Maven)
frontend/                   Angular SPA
docker/
├── Dockerfile              Multi-stage: Angular → Maven → Runtime (JRE + hledger + git)
├── entrypoint.sh           Container-Startskript (generiert Git-Deploy-Key, startet App als Non-Root)
docker-compose.yml          App + PostgreSQL (Produktion & lokaler Test)
docker-compose.dev.yml      Entwicklungs-Abhängigkeiten (authentik, PostgreSQL, Redis, Synapse, Element Web, bank-browser)
docker/matrix/              Lokale Matrix-Dev-Konfiguration (Synapse, Element)
docs/MATRIX_SETUP.md        Matrix-Produktions-Setup
matrix-setup-dev.md         Matrix lokales Dev-Setup (nach authentik-setup.md)
.env.local                  Lokale Umgebungsvariablen für direkte JVM-Ausführung (localhost URLs)
.env.docker                 Lokale Umgebungsvariablen für Container-Test (host.docker.internal URLs)

AI-Agents: Start mit AGENTS.md · Architektur-Details in .agent.md · Code-Konventionen in .github/copilot-instructions.md

Feature-Dokumentation: docs/vier-augen-prinzip.md


Quickstart: Entwicklung

Voraussetzungen: Java 25, Maven 3.9+, Node.js 22+, Docker Desktop.

1. Abhängigkeiten starten

docker compose --env-file .env.local -f docker-compose.dev.yml up -d

Startet authentik (http://localhost:9000), PostgreSQL (localhost:5432), Redis, Synapse (http://localhost:8008), Element Web (http://localhost:8088) und bank-browser (http://localhost:3000). Bank-Tokens aus .env.local — siehe docs/bank-browser-setup.md.

URL Dienst
http://localhost:9000 authentik
http://localhost:8008 Synapse (Matrix API)
http://localhost:8088 Element Web
http://localhost:3000 bank-browser (Volksbank Sidecar)

Erster Start: Login mit akadmin / admin12345, dann App einrichten — siehe authentik-setup.md.
Matrix: Bot-Account und Env-Vars — siehe matrix-setup-dev.md.

2. Backend starten

cd backend && mvn spring-boot:run

Läuft auf http://localhost:8080. Umgebungsvariablen aus .env.local werden von der IDE (z.B. IntelliJ EnvFile-Plugin) oder manuell geladen.

3. Frontend starten

cd frontend && npm install && npm start

Läuft auf http://localhost:4200, proxyt API-Calls an :8080.

Stoppen

docker compose --env-file .env.local -f docker-compose.dev.yml down

Matrix lokal testen

Mit docker-compose.dev.yml läuft ein vollständiger Matrix-Stack für lokale Entwicklung.

  1. Compose starten (siehe Quickstart oben)
  2. Setup-Schritte in matrix-setup-dev.md: Bot-Account, Access Token, .env.local
  3. Backend/Frontend starten, /member/matrix und /admin/matrix/permissions testen

Produktions-Deployment: docs/MATRIX_SETUP.md


Docker-Container testen

Baut das Image und startet es mit lokaler PostgreSQL. Authentik läuft extern via docker-compose.dev.yml.

Da der Container localhost nicht erreichen kann (das wäre der Container selbst), werden die authentik-URLs aufgeteilt:

Variable Zweck Wert lokal
AUTHENTIK_ISSUER_URI Muss dem iss-Claim im Token entsprechen (authentik setzt hier den Host des Token-Requests) http://host.docker.internal:9000/application/o/management/
AUTHENTIK_BASE_URL Backend→Backend Calls (Token, JWKS, UserInfo, API) http://host.docker.internal:9000
AUTHENTIK_AUTHORIZE_URI Browser-Redirect für Login (muss vom User erreichbar sein) http://localhost:9000/application/o/authorize/
# 1. Authentik starten (falls noch nicht läuft)
docker compose --env-file .env.local -f docker-compose.dev.yml up -d

# 2. Image bauen und starten
docker compose --env-file .env.docker up --build

App erreichbar unter http://localhost:8080.

Beim ersten Start wird automatisch ein SSH Deploy Key generiert — den öffentlichen Schlüssel über Admin → Git Deploy Key herunterladen und im Git-Server hinterlegen.

# Stoppen und Volumes löschen
docker compose down -v

Produktion deployen

Gleicher docker-compose.yml, Profile docker. In Produktion ist authentik von überall unter der gleichen URL erreichbar — daher zeigen alle drei Variablen auf dieselbe Basis-URL:

AUTHENTIK_ISSUER_URI=https://auth.node-k.at/application/o/management/
AUTHENTIK_AUTHORIZE_URI=https://auth.node-k.at/application/o/authorize/
AUTHENTIK_BASE_URL=https://auth.node-k.at

OIDC-Discovery wird im Docker-Profil generell nicht verwendet — die Endpoints werden immer explizit aus AUTHENTIK_BASE_URL abgeleitet. Das vermeidet Startup-Abhängigkeiten auf die IdP-Verfügbarkeit.

# .env mit Produktionswerten erstellen (siehe Umgebungsvariablen unten)
docker compose up -d

docker compose liest .env automatisch aus dem selben Verzeichnis — alternativ docker compose --env-file pfad/zu/.env up.

Nach dem ersten Start: Deploy Key über Admin-UI herunterladen und als Deploy Key im Git-Repository (z.B. Forgejo/GitLab) hinterlegen.


Umgebungsvariablen

Alle Variablen werden in der .env-Datei definiert.

Authentik / Auth

Login ist OIDC Authorization Code → Spring HTTP-Session (JSESSIONID). Die SPA speichert keine Access-/Refresh-Tokens; authentik-Refresh-Tokens werden nicht ausgewertet. Session-Laufzeit: server.servlet.session.timeout (8h Inaktivität, Cookie max-age ebenfalls 8h für PWA). Details: docs/roles-and-auth.md.

Variable Beschreibung
AUTHENTIK_ISSUER_URI OIDC Issuer (muss dem iss-Claim in Tokens entsprechen)
AUTHENTIK_AUTHORIZE_URI Authorization-Endpoint (Browser-Redirect für Login)
AUTHENTIK_BASE_URL authentik Base URL für Backend-Calls (Token, JWKS, UserInfo, API)
AUTHENTIK_CLIENT_ID OAuth2 Client ID
AUTHENTIK_CLIENT_SECRET OAuth2 Client Secret
AUTHENTIK_API_TOKEN Service Account Token

Produktion: Alle drei URLs zeigen auf denselben Host (z.B. https://auth.node-k.at). Lokaler Docker-Test: AUTHENTIK_ISSUER_URI und AUTHENTIK_BASE_URL = host.docker.internal:9000, AUTHENTIK_AUTHORIZE_URI = localhost:9000.

Anwendung

Variable Beschreibung Standard
GIT_REPO_URL Git Repository URL (SSH) leer (nur lokales Repo)
APP_MANAGEMENT_URL Öffentliche URL dieser Anwendung (manage.node-k.at) https://manage.node-k.at
MEMBER_PORTAL_URL Authentik-Mitgliederportal (auth.node-k.at) — nicht die Management-App https://auth.node-k.at
DB_PASSWORD PostgreSQL-Passwort Pflichtfeld
DB_USERNAME PostgreSQL-Benutzer management

E-Mail (SMTP)

Only override these if your setup differs from the defaults.

Variable Beschreibung Standard
MAIL_USERNAME SMTP-Benutzername
MAIL_PASSWORD SMTP-Passwort
MAIL_FROM_ADDRESS Standard-Absender-Adresse (Fallback, wenn MAIL_FROM_ADDRESSES leer) noreply@node-k.at
MAIL_FROM_ADDRESSES Kommagetrennte Absender-Adressen für Vorstands-E-Mails Wert von MAIL_FROM_ADDRESS
MAIL_HOST SMTP-Server node-k.at
MAIL_PORT SMTP-Port 465
MAIL_FROM_NAME Absender-Name node-K Vereinsmanagement
MAIL_SSL_ENABLE Implicit SSL true
MAIL_STARTTLS_ENABLE STARTTLS false

Deploy Key: Wird beim Container-Start automatisch unter /data/ssh/git_deploy_key generiert. Der öffentliche Schlüssel ist über die Admin-UI downloadbar.

Matrix (optional)

Variable Beschreibung Standard
MATRIX_HOMESERVER_URL Matrix Homeserver Client API URL leer (deaktiviert)
MATRIX_BOT_USER_ID Bot Matrix-ID (@bot:domain) leer
MATRIX_BOT_ACCESS_TOKEN Bot Access Token leer
MATRIX_HOMESERVER_DOMAIN Homeserver-Domain für ID-Validierung leer
MATRIX_LINK_CODE_TTL_MINUTES Gültigkeit Verifikationscode 15

Ohne Matrix-Env-Vars läuft die App normal; UI zeigt „Matrix Server nicht erreichbar“.


Rollen

Rolle authentik-Gruppe Berechtigungen
MEMBER Club Member Eigenes Profil bearbeiten
BOARD Club Board Member Mitgliederliste, Reports
TREASURER Club Treasurer Buchungen, Beiträge, hledger
AUDITOR (keine — aus members.role) Rechnungsprüfung, Belege ansehen (Lesezugriff); ROLE_AUDITOR wird beim Login aus der DB abgeleitet
ADMIN Club IT-Admin Audit Log, E-Mail, Git Deploy Key Download, Auth-Rollen
TERMINAL Kiosk Terminal Kiosk-Zahlungsintents

Rollen sind kumulativ: ADMIN > TREASURER > BOARD > MEMBER. Mapping passiert in RoleMapper.java basierend auf authentik-Gruppen im OIDC-Token — ausgenommen Rechnungsprüfer (members.role = "Rechnungsprüfer").


Wo bearbeite ich was? (Für Editoren / AI-Agents)

Eine Karte der häufigsten Änderungen. Detaillierte Konventionen in .agent.md.

Neue API-Route hinzufügen

  1. Controller in backend/src/main/java/at/nodek/management/<feature>/<Feature>Controller.java
  2. @PreAuthorize("hasRole('BOARD')") o.ä. nicht vergessen
  3. Service-Methode mit @Transactional (am Service, nicht am Controller)
  4. DTOs unter <feature>/dto/
  5. Frontend-Client in frontend/src/app/core/api/<feature>-api.service.ts — Interfaces in core/models.ts definieren, im Service re-exportieren

Neues Mitglieds-Feld

  1. Flyway-Migration in backend/src/main/resources/db/migration/ als nächste V*__*.sql
  2. Feld in Member.java mit @Column und ggf. @Builder.Default
  3. DTO-Split beachten:
  4. Request-Felder in CreateMemberRequest und/oder UpdateMemberRequest
  5. Update-Logik in MemberService.updateMemberAdmin()immer request.getX() != null Check, sonst überschreibt ein leeres PUT alle Felder mit null
  6. Frontend-Typ in core/models.ts (BoardTableMember / MemberDetail) — wird automatisch re-exportiert über member-api.service.ts
  7. UI in member-modal.component (Edit) und/oder member-view-modal.component (Anzeige)
  8. Tabellenspalte: member-table.component.html

Neue Auth-Rolle / Gruppen-Sync ändern

Neue Frontend-Route (Lazy Load)

  1. Routen-Datei: frontend/src/app/pages/<area>/<area>.routes.ts
  2. In app.routes.ts registrieren mit loadChildren: () => import(...) und canActivate: [authGuard, roleGuard], data: { role: 'ROLE_X' }
  3. Standalone-Component mit separatem .html-Template (Projekt-Konvention)
  4. Control-Flow: @if / @for / @switchkein *ngIf / *ngFor
  5. State via signal() / computed(), Eingaben via input(), Events via output()

Neue E-Mail-Vorlage

  1. Template unter backend/src/main/resources/templates/email/<name>.html (Thymeleaf)
  2. Render via EmailService.renderTemplate(...)

Neue Geplante Aufgabe (Cron)

  • In backend/src/main/java/at/nodek/management/scheduler/@Scheduled mit Idempotenz-Tabelle (Beispiel: MonthlyContributionJob verwendet contribution_ledger mit UNIQUE-Constraint)

Audit-Log-Eintrag

Jede sicherheitsrelevante Aktion: auditService.log("EVENT_TYPE", entityId, "Beschreibung"). Konvention: SCREAMING_SNAKE_CASE für Event-Typen.


Bekannte Stolperfallen

Wichtig für AI-Agents und neue Editoren. Siehe .agent.md für die vollständige Liste.

  • Jackson 3.x: Imports sind tools.jackson.databind.ObjectMapper und tools.jackson.core.type.TypeReferencenicht com.fasterxml.jackson.* (Spring Boot 4 nutzt Jackson 3).
  • Zoneless Angular: Kein zone.js. Templates nutzen @if / @for (keine Strukturdirektiven). State via Signals, nicht via BehaviorSubject.
  • DTO-Trennung Board: Listen liefern BoardTableResponseDto (nur authRoles eager geladen). Detail-Endpoint /api/board/members/{id} für Modals — nie das volle Detail in Listen rendern.
  • Member-Update-Transaktion: PUT /api/board/members/{id} nutzt MemberService.applyBoardUpdate() — eine @Transactional-Methode für alle DB-Writes. Authentik-Sync erfolgt nach Commit im Controller.
  • Optimistic Locking: Member hat @Version-Feld (Long). Concurrent edits → 409 Conflict via GlobalExceptionHandler.
  • Error Handling: GlobalExceptionHandler mappt Exceptions auf strukturiertes JSON { error, message, timestamp }. Frontend-Interceptor zeigt deutsche Meldungen. Typed Exceptions: AuthentikApiException, HledgerException, GitNotReadyException.
  • additional_groups_json ist NOT NULL: Initial-Wert "[]". Neue Member-Entities ohne Builder-Default werfen NPE in Postgres.
  • Template-Referenz vs. viewChild: Wenn dein Template <app-x #foo /> und deine TS-Klasse viewChild('foo') nutzt, gewinnt im Template die Template-Ref. Felder im Template ohne () aufrufen (foo.bar()), in TS via Signal mit () (this.fooRef()?.bar()).
  • Bundle-Size-Budget: Initial-Bundle übersteigt aktuell das 500 kB-Budget (~740 kB). Vor weiteren Imports: Lazy-Loading erwägen oder Budget in angular.json heben.
  • Shared Models: Alle Domain-Interfaces leben in frontend/src/app/core/models.ts. API-Services re-exportieren die Typen. Neue Interfaces dort anlegen, nicht inline in Services.
  • Loading States: Jede Daten-ladende Komponente soll einen loading = signal(true) haben und <app-loading-spinner /> aus shared/ verwenden.