loki bfe91496da
Docker Image / test (push) Canceled after 0s
Docker Image / image (push) Canceled after 0s
Anmeldung Chunk 1: Better-Auth-Basis mit Tabellen und Auth-Routen
2026-10-10 21:09:05 +02:00
2026-10-04 19:59:44 +02:00
2026-10-05 20:42:44 +02:00
2026-10-10 18:20:38 +02:00

MyTime

MyTime ist eine persönliche Web-App zur Urlaubsplanung und Überstunden-Erfassung. Sie läuft als einzelner Docker-Dienst mit SQLite und ist für den Zugriff im Heimnetz gedacht. Es gibt keine Anmeldung: Port niemals ins öffentliche Internet weiterleiten.

Schnellstart (fertiges Image)

Voraussetzungen: Docker Engine, Docker Compose Plugin und Zugriff auf die private Gitea-Container-Registry. Einmalig anmelden; Docker fragt interaktiv nach dem Token mit Paket-Leserecht:

docker login gitea.lokcal.de -u <gitea-benutzer>

Dann im geklonten Repository:

cp .env.example .env
docker compose pull
docker compose up -d

compose.yaml verwendet standardmäßig das fertige Image gitea.lokcal.de/loki/mytime:latest und baut nichts lokal. Der Host-Port kommt aus .env (APP_PORT=3100 in der Vorlage); erreichbar ist die App dann unter http://<server-ip>:3100. Der Status lässt sich mit curl http://127.0.0.1:3100/api/health prüfen.

Lokal entwickeln (Image selbst bauen)

Für Änderungen am Quellcode die separate Dev-Datei verwenden:

cp .env.example .env
docker compose -f compose.dev.yaml up --build -d

compose.dev.yaml baut aus dem lokalen Verzeichnis. Daten und Sicherungen bleiben in beiden Varianten in ./data und ./backups erhalten.

Beim ersten Start in Einstellungen → Arbeitszeit die Sollstunden für alle sieben Wochentage eintragen. Freie Tage erhalten 0; der Knopf „40-h-Woche übernehmen“ füllt Mo–Fr mit 8 Stunden. Danach „Speichern“.

Erste Einrichtung

Öffne Einstellungen → Arbeitszeit. Trage Sollstunden für Montag bis Sonntag ein; 0 bedeutet arbeitsfrei. „40-h-Woche übernehmen“ füllt Montag bis Freitag mit je 8 Stunden und Samstag/Sonntag mit 0. Einzelne Tage kannst du anschließend anpassen. Die angezeigte Wochensumme dient zur Kontrolle. Speichern.

Unter Einstellungen → Urlaub & Bundesland stellst du den Jahresanspruch, den Übertrag und das Bundesland ein. Standard-Bundesland ist Hamburg. Änderungen am Urlaubsanspruch gelten für das im Hauptbereich ausgewählte Jahr; das Bundesland gilt app-weit.

Bedienung

Die Hauptnavigation enthält Übersicht, Zeiterfassung, Feiertage, Verlauf und Einstellungen. Der Hell-/Dunkelmodus wird über das Sonne-/Mond-Symbol im oberen MyTime-Balken umgeschaltet und pro Gerät gespeichert.

Arbeitszeit erfassen

  1. In Zeiterfassung das Datum, Arbeitsbeginn, Arbeitsende und Pause eintragen. Die Pause ist standardmäßig 30 Minuten; 0 ist erlaubt.
  2. Speichern. Positive Zeit über dem Soll des jeweiligen Wochentags wird automatisch gutgeschrieben. Minderstunden werden nicht automatisch abgezogen.
  3. Manuelle Überstunden oder Abbau buchst du in Übersicht. Abbau ist nur möglich, wenn der Überstundenstand dadurch nicht negativ wird; eine Notiz ist optional.
  4. Krankheitstage meldest du ebenfalls in Zeiterfassung: Datum wählen, ganzen oder halben Tag sowie optional eine Notiz eintragen und „Krank melden“. Nur geplante Arbeitstage (keine Wochenenden/Feiertage) sind meldbar. Eine bestehende Meldung lässt sich dort auch wieder löschen.

Urlaub buchen und stornieren

  • In Übersicht Start- und Enddatum sowie ganzen oder halben Tag wählen und buchen. Wochenenden, Tage ohne Sollstunden und Feiertage im ausgewählten Bundesland zählen nicht als Urlaubstage.
  • Auf dem Desktop kannst du den Zeitraum in der Jahrestabelle ziehen. Auf einem Touch-Gerät einen Kalendertag etwa eine halbe Sekunde gedrückt halten, loslassen und den Endtag antippen. Ein normaler Tipp öffnet das Tagesfenster.
  • Das Tagesfenster zeigt Buchungen und Details des Tages. Dort kannst du Urlaub buchen oder eine bestehende Buchung mit Sicherheitsabfrage stornieren.
  • Unter Verlauf → Urlaubsbuchungen findest du Buchungen aller Jahre. Häkchen auswählen und mehrere Buchungen gemeinsam stornieren; der CSV-Export lädt die Liste herunter.
  • Stornierte Einträge landen im Papierkorb. Dort kannst du sie wiederherstellen oder nach einer zweiten Bestätigung endgültig löschen.
  • Die Buchung ist auf den verfügbaren Rest beschränkt: Jahresanspruch + Übertrag − bereits verbrauchte Urlaubstage. Bei einem Zeitraum über den Jahreswechsel wird jedes Jahr einzeln geprüft.
  • Der Übertrag eines Jahres läuft am 31.03. des Folgejahres ab. Kurz vorher und danach zeigt die Übersicht einen Hinweis; Salden und Buchungen bleiben unverändert.

Hauptbereiche

  • Übersicht: Salden, Buchungsformulare und Jahrestabelle. Die Jahrestabelle ist gedreht aufgebaut: Tage als Zeilen, Monate als Spalten. Urlaub ist grün, Krankheit violett, Feiertage rot; die Legende erklärt die Markierungen. Beim Ziehen bleibt der gewählte Zeitraum markiert und kann im Popup direkt gebucht werden.
  • Feiertage → Feiertage: Feiertage des ausgewählten Bundeslands, monatsweise aufgelistet. Ein Feiertag lässt sich anklicken, um zu seinem Datum in der Übersicht zu springen.
  • Feiertage → Brückentage: gespeicherte Empfehlungen von ferien-feiertage.de, nach Datum sortiert und nach Monaten gruppiert. Monatsübergreifende Tage sind in beiden Mini-Kalendern markiert. „Übernehmen“ bucht eine Empfehlung nach Bestätigung direkt; bereits gebuchte oder nicht mehr verfügbare Vorschläge werden ausgeblendet.
  • Verlauf → Jahresübersicht: zwölf Mini-Kalender und Monatssummen. Der Jahresumschalter gilt nur hier und springt beim Verlassen des Tabs wieder auf das App-Jahr zurück. Export als PDF.
  • Verlauf → Überstundenverlauf: automatische und manuelle Buchungen aller Jahre, als CSV exportierbar.
  • Verlauf → Urlaubsbuchungen: Monatsverteilung als Balkendiagramm mit Gesamt- und Durchschnittswerten, darunter die Buchungen aller Jahre mit Mehrfachauswahl zum Stornieren; als CSV exportierbar.
  • Verlauf → Jahresvergleich: Anspruch, Verbrauch, Resturlaub, Krankheitstage sowie automatische, manuelle und gesamte Überstunden für Vorjahr und App-Jahr.
  • Einstellungen → Sicherung: Sicherungsstände ansehen und über „Jetzt sichern“ sofort eine Sicherung erstellen.

Installation auf einem Server

MyTime kann auf dem Server selbst gebaut werden oder als fertiges Image aus der Gitea-Registry laufen.

Empfohlen: fertiges Image

Voraussetzungen:

  • Docker Engine und Docker Compose Plugin
  • Git-Zugriff auf das private Gitea-Repository
  • Leseberechtigung für gitea.lokcal.de/loki/mytime in der Container-Registry

Einmalig am Server an der Registry anmelden (Token mit Paket-Leserecht verwenden; nicht in eine Shell-History oder Datei schreiben):

docker login gitea.lokcal.de -u <gitea-benutzer>

Repository klonen, Port konfigurieren und Image starten:

git clone https://gitea.lokcal.de/loki/mytime.git
cd mytime
cp .env.example .env
# APP_PORT bei Bedarf in .env anpassen, z. B. auf 3100
docker compose pull
docker compose up -d
curl http://127.0.0.1:3100/api/health

Auf einem neuen Server ohne Portkonflikt kann APP_PORT in .env auf 3000 gesetzt werden. Datenbank und Backups liegen in ./data und ./backups neben der Compose-Datei.

Aktualisieren:

cd mytime
git pull
docker compose pull
docker compose up -d --force-recreate
curl http://127.0.0.1:3100/api/health

Image-Build in Gitea Actions

.gitea/workflows/docker.yml führt bei Pushes auf main Tests, Skript-Tests, TypeScript-Prüfung und Produktions-Build aus. Nur wenn alles erfolgreich ist, wird das Image als latest und mit Commit-SHA in die Registry gepusht. Ein Gitea-Actions-Runner und die Container-Registry müssen aktiviert sein. Der Workflow verwendet ACTION_BOT als Registry-Token; alternativ können REGISTRY_USER und REGISTRY_TOKEN als Repository-Secrets gesetzt werden. Der Token braucht Paket-Schreibrecht.

Zum lokalen Bauen und Entwickeln siehe compose.dev.yaml im Schnellstart.

Brückentage-Daten aktualisieren

Die App enthält Scraping-Daten für alle 16 Bundesländer. Sie werden beim normalen Betrieb nicht aus dem Internet geladen; die App funktioniert damit offline. Auf einem Rechner mit Internetzugang im Repository ausführen:

npm ci
npm run scrape:bridge
npm test -- --run
npm run test:scripts
npx tsc --noEmit

Standardmäßig lädt das Skript das laufende und das nächste Jahr und erhält bereits gespeicherte Jahre. Optional lassen sich Jahre und Bundesländer angeben:

npm run scrape:bridge -- --years=2028,2029,2030 --states=HH,BY

Danach Änderungen committen und nach Gitea pushen. Die Action baut ein aktualisiertes Image. Für nicht gespeicherte Jahre zeigt die App einen Hinweis statt lokal berechneter Empfehlungen.

Datensicherung und Wiederherstellung

Die App erstellt wöchentlich automatisch eine konsistente SQLite-Sicherung und behält höchstens fünf Dateien in ./backups. In Einstellungen → Sicherung kann zusätzlich jederzeit eine Sicherung manuell erstellt und der Sicherungsstand kontrolliert werden.

Sicherung zurückspielen

  1. Im Verzeichnis mit der Compose-Datei den Dienst stoppen:

    docker compose stop app
    

    Bei lokaler Entwicklung stattdessen docker compose -f compose.dev.yaml stop app verwenden.

  2. WAL-Seitendateien der aktuellen Datenbank entfernen, dann Sicherung einspielen:

    rm -f data/app.sqlite3-wal data/app.sqlite3-shm
    cp backups/<backup-datei>.sqlite3 data/app.sqlite3
    
  3. Dienst wieder starten:

    docker compose start app
    

    Bei lokaler Entwicklung stattdessen docker compose -f compose.dev.yaml start app verwenden.

  4. http://<server-ip>:<APP_PORT>/api/health prüfen und anschließend Salden und Buchungen in der App kontrollieren.

Wichtig: Die App verwendet SQLite im WAL-Modus. Deshalb vor dem Restore immer stoppen und die alten -wal- und -shm-Dateien löschen; sonst können alte Transaktionen mit der eingespielten Sicherung vermischt werden.

Sicherheit und Daten

  • MyTime hat keine Anmeldung. Nur im Heimnetz betreiben, keinen Router-Port ins Internet weiterleiten und den Port in der Firewall auf das LAN begrenzen.
  • Der Container startet und läuft als Non-Root-User node (UID:GID 1000:1000); compose.yaml und compose.dev.yaml erzwingen das zusätzlich per user: "1000:1000". Einmalige Migration bestehender Daten: sudo chown -R 1000:1000 data backups.
  • Datenbank: ./data/app.sqlite3; Sicherungen: ./backups/.
  • Daten und Sicherungen sind in .gitignore ausgeschlossen und werden nicht mit dem Quellcode veröffentlicht.

Entwicklung und Tests

Voraussetzungen: Node.js 22 und npm.

npm ci
npm run dev
npm test -- --run
npm run test:scripts
npx tsc --noEmit
npm run build
S
Description
Persönliche Urlaubsplanung und Überstunden-Erfassung (MyTime)
Readme
1.2 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 95.1%
CSS 3.4%
JavaScript 1.2%
HTML 0.2%
Dockerfile 0.1%