No description
  • Python 82.1%
  • HTML 14.6%
  • CSS 1.3%
  • Shell 0.6%
  • Dockerfile 0.6%
  • Other 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Mathias Kessler a1c2c4765c
All checks were successful
build / build (push) Successful in 9s
Merge pull request 'Add CLAUDE.md and project plan' (#12) from develop into main
Reviewed-on: #12
2026-11-01 21:18:16 +01:00
.forgejo/workflows Add build workflow, seed data and README 2026-11-01 20:48:35 +01:00
alembic Add setlists with ordering and snapshots 2026-11-01 20:42:43 +01:00
assets Add groups, invitations and instruments 2026-11-01 20:03:48 +01:00
dev Add OIDC login, sessions and CSRF protection 2026-11-01 19:57:06 +01:00
docs Add CLAUDE.md and project plan 2026-11-01 21:04:22 +01:00
scripts Speed up CI by removing apt and pip 2026-11-01 20:42:30 +01:00
src/notenwart Add build workflow, seed data and README 2026-11-01 20:48:35 +01:00
tests Add build workflow, seed data and README 2026-11-01 20:48:35 +01:00
.dockerignore Add project scaffold 2026-11-01 19:53:13 +01:00
.env.example Add project scaffold 2026-11-01 19:53:13 +01:00
.gitignore Add OIDC login, sessions and CSRF protection 2026-11-01 19:57:06 +01:00
alembic.ini Add project scaffold 2026-11-01 19:53:13 +01:00
CLAUDE.md Add CLAUDE.md and project plan 2026-11-01 21:04:22 +01:00
compose.dev.yaml Add OIDC login, sessions and CSRF protection 2026-11-01 19:57:06 +01:00
compose.yaml Add project scaffold 2026-11-01 19:53:13 +01:00
Dockerfile Add project scaffold 2026-11-01 19:53:13 +01:00
LICENSE Add project scaffold 2026-11-01 19:53:13 +01:00
Makefile Add build workflow, seed data and README 2026-11-01 20:48:35 +01:00
pyproject.toml Add OIDC login, sessions and CSRF protection 2026-11-01 19:57:06 +01:00
README.md Add build workflow, seed data and README 2026-11-01 20:48:35 +01:00
uv.lock Add OIDC login, sessions and CSRF protection 2026-11-01 19:57:06 +01:00

Notenwart

Selbst gehostetes Notenarchiv und Setlists für Musikvereine: Notensätze mit Metadaten, Notizen und PDF-Stimmen, Setlists mit A4-Druckansicht und öffentlichem Link. Mehrere Gruppen teilen sich eine Installation und bleiben streng getrennt.

Lizenz: AGPL-3.0-or-later.

Funktionen

  • Anmeldung nur über OIDC, keine lokalen Passwörter
  • Gruppen mit den Rollen Admin, Notenwart und Mitglied, Beitritt über Einladungslink
  • Globaler Stückekatalog, Notensätze pro Gruppe, Suche mit Tippfehlertoleranz
  • PDF-Upload pro Stimme, Mitglieder sehen zuerst die Stimmen ihres Instruments
  • Setlists mit Drag-and-Drop, Dauer-Summe und eingefrorenem Stand nach dem Auftritt
  • A4-Druckansicht im Design der Gruppe, widerrufbarer öffentlicher Link

Rollen

Rolle Darf
Mitglied lesen, alle PDFs der Gruppe laden, Notizen schreiben, eigene Instrumente pflegen
Notenwart zusätzlich Stücke, Notensätze, Uploads, Setlists und öffentliche Links
Admin zusätzlich Mitglieder, Einladungen und Gruppendesign
Superadmin Gruppen anlegen, Zugriff auf alle Gruppen, Instrumente umbenennen und löschen

Entwicklung

Voraussetzungen: uv, Docker und einmalig das Netzwerk, das compose.yaml erwartet:

docker network create traefik
cp .env.example .env
make dev

make dev startet Postgres und Dex in Docker, baut die CSS, führt die Migrationen aus und startet die App auf http://localhost:8000. Dex ersetzt lokal PocketID, die Testnutzer stehen in dev/dex.yaml. admin@notenwart.test ist Superadmin.

Befehl Zweck
make seed Demo-Gruppen, Stücke und eine Setlist anlegen (nur für die Entwicklung)
make css-watch Tailwind-CSS bei Änderungen neu bauen
make test Tests gegen eine eigene Test-Datenbank
make lint ruff und Lizenzprüfung aller Abhängigkeiten
make format Code formatieren

Das Image lässt sich auch lokal bauen und starten, auf ARM64 wie auf x86. Dex ist im Container nicht unter localhost erreichbar, ein Login funktioniert dort also nicht:

docker compose -f compose.yaml -f compose.dev.yaml up -d --build --wait notenwart

Danach antwortet die App auf http://127.0.0.1:8001/health.

Arbeitsweise

Entwickelt wird nach Git Flow: pro Feature ein Branch feature/* von develop, Merge per Squash-PR. Ein Merge von develop nach main erzeugt ein Release.

Echte Noten gehören nicht in dieses Repository: Es ist öffentlich und die Noten sind urheberrechtlich geschützt. Tests arbeiten mit synthetischen PDFs.

Neue Abhängigkeiten müssen AGPL-kompatibel sein, make lint prüft das gegen die Liste in scripts/lint.sh.

Konfiguration

Alle Werte kommen aus der Umgebung, siehe .env.example.

Variable Bedeutung
BASE_URL Öffentliche Adresse der App. Mit https:// werden Cookies als Secure gesetzt
SECRET_KEY Signiert die Sessions, erzeugen mit openssl rand -hex 32
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD Datenbank. Das Passwort landet in einer URL, also nur URL-sichere Zeichen verwenden
NOTENWART_DB_DIR Hostpfad der Datenbank
NOTENWART_DATA_DIR Hostpfad der PDFs und Logos
PUID, PGID Benutzer des App-Containers, muss in NOTENWART_DATA_DIR schreiben dürfen
OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET OIDC-Client
BOOTSTRAP_ADMIN_EMAILS Kommagetrennte Adressen, die beim Login Superadmin werden
MAX_UPLOAD_MB Größenlimit für einen PDF-Upload
TZ Zeitzone des Containers

PocketID einrichten

  1. Unter Administration → OIDC Clients mit Add OIDC Client einen Client Notenwart anlegen.
  2. Als Callback-URL https://notenwart.makeitsystems.de/auth/callback eintragen.
  3. Auf dem Tab General die Option PKCE aktivieren und speichern.
  4. Client-ID und Secret als OIDC_CLIENT_ID und OIDC_CLIENT_SECRET eintragen. OIDC_ISSUER ist https://id.makeitsystems.de.
  5. Die Adressen der Admins als verifiziert markieren: unter Administration → Application Configuration → Email die Option Emails verified by default aktivieren und die Benutzer unter Administration → Users verifizieren.

Der fünfte Schritt ist nötig: Eine Adresse aus BOOTSTRAP_ADMIN_EMAILS macht nur dann zum Superadmin, wenn der IdP sie mit email_verified: true bestätigt. Die Prüfung läuft bei jedem Login.

Das schützt nur, solange niemand eine fremde Adresse als verifiziert übernehmen kann. Benutzer dürfen ihre E-Mail-Adresse in PocketID also nicht selbst ändern können, wenn Emails verified by default aktiv ist.

Deployment im Homelab

compose.yaml passt zu den Konventionen des Homelabs: Netzwerk traefik, kein Host-Port, Bind-Mounts in Langform, Ressourcenlimits. Traefik leitet nach dem Service-Namen auf notenwart.makeitsystems.de weiter. Die Kette chain-default ist Absicht: Mit chain-tinyauth wären die öffentlichen Setlist-Links nicht mehr erreichbar.

Vor dem ersten Start:

  1. In .env die Homelab-Werte aus .env.example setzen. Secrets kommen aus Dockhand.
  2. Das Verzeichnis NOTENWART_DATA_DIR anlegen und PUID:PGID zum Besitzer machen.
  3. Das Icon unter /mnt/cache/appdata/icons/notenwart.png ablegen.

Die Migrationen laufen beim Start des Containers. Anschließend mit einer Adresse aus BOOTSTRAP_ADMIN_EMAILS anmelden, Gruppen anlegen und unter Mitglieder die Einladungslinks erzeugen. Logo und Farben trägt ein Admin unter Einstellungen ein.

Image und Releases

.forgejo/workflows/build.yaml baut bei jedem Push auf main das Image für linux/amd64, schiebt es als latest und YYYY.MM.N in die Forgejo-Registry und legt ein Release an. Reicht das Workflow-Token nicht, die Repo-Secrets REGISTRY_USER und REGISTRY_TOKEN setzen.

Sicherung

Zu sichern sind beide Verzeichnisse, NOTENWART_DB_DIR und NOTENWART_DATA_DIR. Die Datenbank allein reicht nicht, sie enthält keine PDFs.