Files
ferdi2goandClaude Fable 5.1 42d495c54e Tauschanfragen gegen offene Plätze erlauben und Lücken nachbesetzen
Ein Wunschtag ohne Tauschpartner bedeutet jetzt: die Person übernimmt
dort einen offenen Platz; ihr alter Platz wird beim Ausführen sofort
fair nachbesetzt, ohne sie selbst. Rollen werden bei allen Tauschformen
geprüft. Bearbeiter können Person und Wunschtag einer Anfrage nachtragen,
etwa aus der Notiz. Der Anfragedialog zeigt, was am Wunschtag los ist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-15 11:55:53 +00:00

158 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Rotatory
Rotatory plant die Moderation des werktäglichen Morning Meetings: Pro Tag werden ein
**Hauptmoderator** und ein **Nebenmoderator** aus der Belegschaft fair und zufällig
ausgelost. Die Monatsansicht zeigt auf jedem Tag die Fotos der beiden Personen. Der fertige
Plan lässt sich per Knopfdruck als Termine in einen Nextcloud-Kalender schreiben.
<img src="public/logo/rotatory-mark.svg" alt="" width="64" height="64" align="left">
## Funktionen
- Personen mit Vor- und Nachname, optionaler E-Mail, Foto (Upload, wird im Browser auf
320 px zugeschnitten) und Rolle: Hauptmoderation / Nebenmoderation / beides / keins
(Nicht-Moderator). Feste freie Wochentage für Teilzeitkräfte. Inaktive Personen bleiben
angelegt, werden aber nicht ausgelost.
- Personenimport aus Nextcloud: alle Konten aus dem Systemadressbuch zur Auswahl, Profilbilder
werden übernommen.
- Abwesenheiten (Urlaub, geplante Krankheit, Frei, Sonstiges) je Person mit Zeitraum – manuell
oder importiert aus einem Nextcloud-Kalender mit Terminen wie „Vorname Nachname (Urlaub)",
„… (krank)", „… (frei)". Wiederholungen werden aufgelöst, Namen den Personen zugeordnet,
nicht zuordenbare Namen aufgelistet.
- Feiertage: gesetzliche Feiertage je Bundesland auf Knopfdruck erzeugen, dazu eigene
betriebsfreie Tage. An diesen Tagen wird nicht geplant.
- Auslosung für beliebige Monatsbereiche. Regeln: nur Mo–Fr, keine Feiertage, keine
Abwesenden, niemand an zwei Werktagen hintereinander (wenn vermeidbar), Einsätze
gleichmäßig verteilt (Fairness-Fenster berücksichtigt auch vergangene Einsätze), Rollen
werden abgewechselt, dieselbe Paarung wiederholt sich ungern.
- Einzelne Tage manuell setzen, fixieren (überlebt jede Neuauslosung), neu auslosen oder
als „Kein Meeting" markieren.
- Einsatzstatistik je Monat.
- Export als ICS-Datei oder direkt per CalDAV in einen Nextcloud-Kalender: wahlweise ein
vorhandener (auch geteilter) Kalender oder ein neu angelegter. Wiederholtes Schreiben
aktualisiert bestehende Termine und löscht entfallene; fremde Termine im Zeitraum können auf
Wunsch mit entfernt werden.
## Installation
Voraussetzung: Node.js 20 oder neuer.
```bash
npm install
```
## Starten
```bash
npm run dev # Entwicklung, startet bei Änderungen neu
npm start # Produktion
```
Die App lauscht auf `PORT` (Vorgabe 3000) und speichert alle Daten unter `VCH_DATA_DIR`
(Vorgabe `./data`): eine JSON-Datei plus die Fotos. Ein Datenbankserver ist nicht nötig.
Eine `.env` im Projektstamm wird beim Start gelesen (bereits gesetzte Variablen gewinnen).
Beim ersten Start werden die gesetzlichen Feiertage für dieses und nächstes Jahr angelegt;
Vorgaben: Bayern, Meeting 09:30 Uhr, 15 Minuten.
## Konfiguration
Alle Variablen sind optional, siehe `.env.example`:
| Variable | Bedeutung |
|---|---|
| `NEXTCLOUD_URL` | Basis-URL der Nextcloud, z. B. `https://cloud.example.de` |
| `NEXTCLOUD_USER` | Anmeldename, E-Mail-Adresse geht auch; die Benutzer-ID wird per CalDAV-Discovery ermittelt |
| `NEXTCLOUD_APP_PASSWORD` | App-Passwort (Nextcloud → Einstellungen → Sicherheit → Geräte & Sitzungen) |
| `NEXTCLOUD_CALENDAR` | ID des eigenen Kalenders, falls kein vorhandener Zielkalender gewählt wird (Vorgabe `morning-meeting`) |
| `NEXTCLOUD_INSECURE_TLS` | `true`, wenn die Nextcloud ein selbstsigniertes Zertifikat nutzt |
| `EDIT_PASSWORD` | Bearbeitungspasswort. Wenn gesetzt, sehen alle nur den Kalender; Auslosen, Personen, Abwesenheiten, Einstellungen und Nextcloud erfordern die Anmeldung über „Anmelden" in der Kopfzeile |
| `APP_PASSWORD` | Wenn gesetzt, schützt HTTP Basic Auth die ganze App inklusive Ansehen (Benutzername beliebig) |
Ohne Nextcloud-Variablen läuft die App vollständig, nur der Button „Go – schreiben" ist
deaktiviert; der ICS-Download bleibt verfügbar.
## Teilen im Team
Die Adresse der App kann an alle weitergegeben werden. Mit gesetztem `EDIT_PASSWORD` sehen
Besucher den Monatskalender mit Fotos und die Einsatzstatistik, aber keine E-Mail-Adressen,
Notizen oder Abwesenheiten, und sie können nichts ändern. Wer bearbeiten will, klickt oben rechts
auf „Anmelden". Die Anmeldung gilt 30 Tage im jeweiligen Browser; nach fünf falschen Versuchen
wartet der Server eine Minute. Ohne `EDIT_PASSWORD` darf jeder alles, wie bei einem Werkzeug
für eine einzelne Person.
## Tauschanfragen
Wer an seinem Tag nicht kann, klickt den Tag im Kalender an, wählt seinen Namen und schreibt
eine Notiz. Optional dazu: eine Person, mit der getauscht werden soll, und ein Wunschtag.
Ohne Person bedeutet der Wunschtag, dass am Wunschtag ein noch offener Platz übernommen wird.
Dafür ist keine Anmeldung nötig; pro Adresse sind zehn Anfragen je Stunde möglich. Der Tag
bekommt im Kalender eine Markierung. Bearbeiter sehen alle Anfragen unter „Anfragen" mit Zähler
in der Navigation und entscheiden: „Ausführen" tauscht wie gewünscht (über Kreuz, Übernahme
des Tages oder Wechsel auf den offenen Platz; der frei werdende Platz wird sofort fair
nachbesetzt), „Wunsch anpassen" trägt Person oder Wunschtag nach, etwa aus der Notiz, „Tag
öffnen" lässt manuell wählen, „Erledigt" und „Ablehnen" schließen die Anfrage ohne Änderung.
Rollen werden beachtet: Wer nur Hauptmoderation macht, bekommt keinen Nebenplatz. Nach einem
Tausch den Zeitraum erneut nach Nextcloud schreiben.
## Bugs melden
Unten rechts sitzt ein Käfer-Button. Ein Klick nimmt den sichtbaren Bildschirm auf (mit der
selbst gehosteten Bibliothek html2canvas, die die Seite aus dem Seiteninhalt nachzeichnet),
zeigt ihn als Vorschau, in der sich rote Rechtecke aufziehen lassen, und fragt nach einer
Beschreibung und optional dem Namen. Dafür ist keine Anmeldung nötig; pro Adresse sind zehn
Meldungen je Stunde möglich. Bearbeiter sehen die Meldungen unter „Bugs" mit Zähler.
„Prompt kopieren" legt eine fertige Anweisung für Claude Code in die Zwischenablage, die
Vorlage dafür steht in den Einstellungen; „Screenshot kopieren" das Bild dazu. Bilder in die
Zwischenablage legen erlauben Browser nur über https; auf einer http-Adresse öffnet
„Screenshot öffnen" das Bild zum Kopieren per Rechtsklick. Screenshots sind nur angemeldet
abrufbar, weil sie Namen und Planung zeigen.
## Nextcloud
1. Umgebungsvariablen setzen und App neu starten.
2. **Personen** → „Aus Nextcloud importieren …": Konten auswählen, Fotos kommen mit.
3. **Abwesenheiten** → Quellkalender (z. B. „Urlaub/Krankheit") und Zeitraum wählen,
importieren. Vor jeder Auslosung wiederholen, damit neue Urlaube berücksichtigt sind.
4. **Kalender** → „Auslosen …" für die kommenden Monate.
5. **Kalender** → „Nextcloud …": Zielkalender wählen (ein vorhandener geteilter Kalender wird
vorgeschlagen), **Verbindung testen**, Zeitraum wählen und **Go – schreiben**. Je Werktag
entsteht ein Termin „Morning Meeting: Haupt / Neben" zur eingestellten Uhrzeit.
Termine tragen eine stabile UID je Tag (`rotatory-<datum>@<host>`), daher aktualisiert ein
erneutes Schreiben statt zu duplizieren. Termine anderer Herkunft im Zeitraum werden gezählt
und nur auf ausdrücklichen Wunsch (Häkchen) entfernt.
Mit der Einstellung „Moderatoren als Teilnehmer eintragen" werden die beiden Personen (bei
hinterlegter E-Mail) als Teilnehmer eingetragen; Nextcloud verschickt dann Einladungen.
## Tests und Prüfung
```bash
npm test # Auslosung, Feiertage, ICS, iCal/vCard-Parser, CalDAV-Client (mit simulierter Nextcloud)
npm run lint # Syntaxprüfung aller Quelldateien
```
## Aufbau
```
server/
index.js Express-App, REST-API, statische Dateien
store.js JSON-Speicher (atomar) und Fotoablage
scheduler.js Auslosungslogik (rein, testbar)
holidays.js Gesetzliche Feiertage je Bundesland
ics.js iCalendar-Erzeugung
nextcloud.js CalDAV/CardDAV-Client (Discovery, PROPFIND, MKCALENDAR, REPORT, PUT, DELETE)
requests.js Tauschanfragen prüfen und ausführen
bugs.js Bug-Meldungen: Screenshot prüfen, Prompt-Vorlage
auth.js Bearbeitungsschutz (Cookie, Bremse)
ical.js iCalendar- und vCard-Leser, Namenszuordnung
env.js .env-Leser
public/
index.html, app.js, style.css Oberfläche ohne Framework, relative Pfade
test/ node:test
```
Abhängigkeiten: nur `express`; im Browser zusätzlich die selbst gehostete Bibliothek
html2canvas (`public/vendor/`, MIT) für Screenshots in Bug-Meldungen. Fotos werden im Browser
per Canvas verkleinert, `fetch` und `crypto` kommen aus Node.