Animierte Marke aus zwei Bögen mit Pfeilspitzen: dreht sich beim Laden einmal abbremsend und bleibt in der symmetrischen Endstellung; bei reduzierter Bewegung sofort statisch. Farbe folgt dem Text (Weiß auf tradeo-Blau). Statische, animierte und Favicon-Variante unter public/logo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
127 lines
6.2 KiB
Markdown
127 lines
6.2 KiB
Markdown
# 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.
|
||
|
||
## 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)
|
||
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`. Fotos werden im Browser per Canvas verkleinert, `fetch` und
|
||
`crypto` kommen aus Node.
|