Dokumentation

Deployment, Konfiguration, Schichtplanung, Projektzeit, Barrierefreiheit & Erweiterungen

1. Docker-Images

Docker Hub

klokkme/klokk

hub.docker.com/r/klokkme/klokk

GitHub Container Registry

ghcr.io/klokk-me/klokk

ghcr.io packages

TagBeschreibung
stableProduktionsreif. Empfohlen für den Self-Hosting-Betrieb.
latestNeueste Veröffentlichung; kann aktuelle Fixes enthalten, die noch nicht nach stable übernommen wurden.

2. Schnellstart

Am einfachsten läuft Klokk mit SQLite — ohne externe Datenbank. Für den Produktivbetrieb wird ein Volume-Mount benötigt, damit die Daten über Container-Neustarts hinweg erhalten bleiben.

Docker run (SQLite)

docker run -d \
  --name klokk \
  -p 8080:8080 \
  -v klokk-data:/app/data \
  -e SESSION_SECRET="$(openssl rand -hex 32)" \
  -e CSRF_KEY="$(openssl rand -hex 32)" \
  -e SESSION_SECURE_COOKIE=false \
  -e BASE_URL=http://localhost:8080 \
  klokkme/klokk:stable

docker-compose.yml (SQLite)

services:
  klokk:
    image: klokkme/klokk:stable
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - klokk-data:/app/data
    environment:
      BASE_URL: "http://localhost:8080"
      SESSION_SECRET: "change-me-min-32-chars-random-string"
      CSRF_KEY: "change-me-min-32-chars-random-string"
      SESSION_SECURE_COOKIE: "false"

volumes:
  klokk-data:
Nach dem ersten Start: Melden Sie sich mit dem Benutzernamen admin (E-Mail admin@localhost) und dem Standardpasswort an und ändern Sie es anschließend sofort. Siehe DEFAULT_ADMIN_PASSWORD.

3. Umgebungsvariablen

Die gesamte Konfiguration erfolgt über Umgebungsvariablen. Mit Erforderlich markierte Variablen haben keinen Standardwert und müssen vor dem Start von Klokk gesetzt werden.

Anwendung

VariableStandardBeschreibung
APP_ENVdevLaufzeitmodus: production oder dev. Für echte Deployments production setzen; dev lockert einige Sicherheitsprüfungen.
PORT8080HTTP-Listen-Port innerhalb des Containers.
BASE_URLhttp://localhost:8080Öffentliche Basis-URL (ohne abschließenden Schrägstrich). Wird für Links in E-Mails verwendet.
LOG_LEVELwarnLog-Ausführlichkeit: debug, info, warn, error.
LOCALES_PATHlocalesPfad zum Verzeichnis der Locale-Dateien (relativ zum Binary oder absolut).

Datenbank

VariableStandardBeschreibung
DB_DRIVERsqliteDatenbank-Backend: sqlite oder postgres.
DB_SQLITE_PATH./data/klokk.dbPfad zur SQLite-Datei. /app/data als Volume einbinden, damit sie erhalten bleibt.
DB_DSNPostgreSQL-Verbindungszeichenfolge, z. B. postgres://user:pass@host:5432/db?sslmode=disable. Erforderlich bei DB_DRIVER=postgres.
DB_MAX_OPEN_CONNS25Maximale offene DB-Verbindungen (nur PostgreSQL).
DB_MAX_IDLE_CONNS5Maximale ungenutzte DB-Verbindungen (nur PostgreSQL).
DB_CONN_MAX_LIFETIME_MINUTES5Maximale Verbindungslebensdauer in Minuten (nur PostgreSQL).

SicherheitErforderlich

VariableStandardBeschreibung
SESSION_SECRETGeheimnis zum Signieren der Session-Cookies. Mind. 32 Zeichen. Muss geändert werden. Erzeugen: openssl rand -hex 32
CSRF_KEYGeheimnis zum Signieren der CSRF-Token. Mind. 32 Zeichen. Muss geändert werden. Erzeugen: openssl rand -hex 32
SESSION_SECURE_COOKIEfalseIm Produktivbetrieb true (erfordert HTTPS). false für HTTP/localhost.
SESSION_SAME_SITElaxCookie-SameSite-Richtlinie: strict, lax oder none.
SESSION_MAX_AGE_HOURS24Standard-Sitzungsdauer in Stunden.

Authentifizierung

VariableStandardBeschreibung
REMEMBER_ME_ENABLEDtrueCheckbox „Angemeldet bleiben" auf der Login-Seite anzeigen.
MFA_TRUST_ENABLEDtrueCheckbox „Diesem Gerät vertrauen" auf der MFA-Seite anzeigen.
MFA_TRUST_DAYS30Dauer in Tagen für gemerkte Sitzungen und vertrauenswürdige MFA-Geräte.
DEFAULT_ADMIN_PASSWORDAdmin@Klokk1Passwort für das anfängliche Admin-Konto (Benutzername admin, E-Mail admin@localhost). Wird nur beim ersten Start verwendet. Nach dem Login sofort ändern.

Admin-Zugriffskontrolle

VariableStandardBeschreibung
ADMIN_IP_ALLOWLISTemptyKommagetrennte IPs/CIDRs mit Zugriff auf /admin/*. Leer = keine Einschränkung. X-Forwarded-For wird hinter Reverse-Proxys berücksichtigt.
SUPER_ADMIN_IP_ALLOWLISTemptyZusätzliche Allowlist für reine super_admin-Routen (/admin/settings, /admin/companies, /admin/audit). Ergänzt ADMIN_IP_ALLOWLIST.

Passwortrichtlinie

VariableStandardBeschreibung
PASSWORD_MIN_LENGTH12Minimale Passwortlänge.
PASSWORD_REQUIRE_UPPERtrueMindestens einen Großbuchstaben verlangen.
PASSWORD_REQUIRE_LOWERtrueMindestens einen Kleinbuchstaben verlangen.
PASSWORD_REQUIRE_NUMBERtrueMindestens eine Ziffer verlangen.
PASSWORD_REQUIRE_SPECIALtrueMindestens ein Sonderzeichen verlangen.
PASSWORD_MAX_HISTORY5Anzahl gemerkter früherer Passwörter (verhindert Wiederverwendung). 0 = deaktiviert.
PASSWORD_EXPIRY_DAYS0Passwortablauf in Tagen. 0 = läuft nie ab.

Rate-Limiting

VariableStandardBeschreibung
RATE_LIMIT_LOGIN_PER_MINUTE10Maximale Login-Versuche pro IP und Minute.
RATE_LIMIT_MFA_PER_MINUTE10Maximale MFA-Versuche pro IP und Minute.
RATE_API_PER_MINUTE100Maximale API-/allgemeine Anfragen pro IP und Minute.
AUTH_LOCKOUT_THRESHOLD0Fehlgeschlagene Login-Versuche bis zur Kontosperrung. 0 = deaktiviert.
AUTH_LOCKOUT_DURATION_MINUTES15Dauer der Kontosperrung in Minuten.

Internationalisierung

VariableStandardBeschreibung
I18N_DEFAULT_LOCALEenStandardsprache für neue Nutzer und die Login-Seite: en oder de.
I18N_AVAILABLE_LOCALESen,deKommagetrennte Liste aktivierter Sprachen.

Arbeitszeit-Standardwerte

Wird beim ersten Start auf den Admin-Seed-Nutzer angewendet. Pro-Nutzer-Werte werden danach in der App verwaltet.

VariableStandardBeschreibung
DEFAULT_WEEKLY_HOURS40Standard-Wochenarbeitszeit.
DEFAULT_ANNUAL_LEAVE_DAYS30Standard-Jahresurlaubstage.

Schichtplanung

Die Schichtplanung selbst wird pro Firma in der App aktiviert (Admin → Companies), nicht über Umgebungsvariablen. Siehe Schichtplanung unten für den vollständigen Ablauf. Die einzige serverseitige Einstellung ist die Push-Erinnerung vor Schichtbeginn:

VariableStandardBeschreibung
SHIFT_REMINDER_HOURS0Sendet so viele Stunden vor Beginn einer veröffentlichten Schicht eine Push-Erinnerung. Wird einmal pro Schicht an Mitarbeitende gesendet, die die Push-Benachrichtigung „Schichtplan veröffentlicht oder geändert" aktiviert haben. 0 = deaktiviert.

SMTP (E-Mail)

VariableStandardBeschreibung
SMTP_HOSTemptySMTP-Server-Hostname. Leer lassen, um den E-Mail-Versand komplett zu deaktivieren.
SMTP_PORT587SMTP-Server-Port. 587 für STARTTLS, 465 für implizites TLS.
SMTP_USERSMTP-Benutzername.
SMTP_PASSSMTP-Passwort.
SMTP_TLSfalsetrue = implizites TLS (Port 465). false = STARTTLS (Port 587).
SMTP_FROMemptyAbsenderadresse für ausgehende E-Mails. Leer lassen zum Deaktivieren.

API & Erweiterungen

Klokk bietet eine schreibgeschützte öffentliche REST-API unter /api/v1/*(/status, /users,/clock/states, /time/entries,/companies). Anfragen werden mit einem API-Schlüssel authentifiziert und pro Scope autorisiert (z. B. read:users, read:time_entries) und auf 60 Anfragen pro Minute und IP begrenzt.

Super-Admins verwalten Integrationen unter API & Erweiterungen(/admin/extensions). Jede Integration bündelt einen API-Schlüssel, seine Scopes und einen Verbindungsmodus:

  • Nur API — die Erweiterung ruft die obige REST-API mit ihrem Schlüssel auf.
  • Webhooks — Klokk sendet bei Ein-/Ausstempeln und Abwesenheitsereignissen ausgehende HTTP-POSTs.
  • WebSocket — die Erweiterung öffnet eine dauerhafte eingehende Verbindung unter GET /api/v1/extension/connect.

Mit EXTENSIONS_ENABLED=false wird das Erweiterungs-Subsystem auf Netzwerkebene abgeschaltet. Die oben aufgeführten schreibgeschützten REST-API-Endpunkte bleiben verfügbar; nur die Webhook-/WebSocket-Funktionen unten werden deaktiviert.

VariableStandardBeschreibung
EXTENSIONS_ENABLEDtrueAktiviert das Erweiterungs-API-Subsystem. Bei false:
  • /admin/extensions und alle Unterrouten liefern 404
  • Der WebSocket-Endpunkt /api/v1/extension/connect wird nicht registriert
  • Der Versand ausgehender Webhooks entfällt vollständig
  • Es werden keine ExtensionHub-Goroutinen gestartet
WEBHOOK_ALLOW_PRIVATE_TARGETSfalseSSRF-Schutz für ausgehende Webhooks. Standardmäßig werden Webhook-URLs abgelehnt, die auf Loopback-, private oder Link-Local-Adressen auflösen (auch über Redirects und DNS-Rebinding). Nur auf true setzen, wenn Webhooks bewusst an einen Endpunkt im internen Netz zugestellt werden sollen.

4. Reverse-Proxy

Wenn Klokk hinter einem Reverse-Proxy läuft, setzen Sie zusätzlich zur Proxy-Konfiguration diese beiden Variablen:

  • SESSION_SECURE_COOKIE=true setzen — erforderlich bei Auslieferung über HTTPS.
  • BASE_URL=https://yourdomain.com setzen — ohne abschließenden Schrägstrich.

nginx

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # TLS config omitted — use certbot or similar

    location / {
        proxy_pass         http://localhost:8080;
        proxy_set_header   Host              $host;
        proxy_set_header   X-Real-IP         $remote_addr;
        proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

Caddy

yourdomain.com {
    reverse_proxy localhost:8080
}

Caddy stellt TLS-Zertifikate automatisch über Let's Encrypt bereit und erneuert sie — keine zusätzliche TLS-Konfiguration nötig.

5. Schichtplanung

Mit der Schichtplanung erstellen Admins und Manager Wochenpläne aus wiederverwendbaren Schichtvorlagen, veröffentlichen sie an die Mitarbeitenden und regeln den Alltag über Tausch, offene Schichten und Verfügbarkeiten — mit eingebauten Prüfungen nach dem Arbeitszeitgesetz (ArbZG). Es ist optional: Ein Mandant muss es aktivieren, und nur Nutzer mit dem Arbeitszeitmodell schichtbasiert beziehen ihre Sollstunden aus dem Dienstplan.

a. Schichten aktivieren

Ein Super-Admin aktiviert die Funktion pro Firma unter Admin → Companies:

  • Schichtplanung — aktiviert Schichtvorlagen und Dienstpläne für die Firma.
  • Ankündigungsfrist Dienstplan (Tage) — erforderliche Vorlaufzeit, bevor ein Dienstplan veröffentlicht werden darf (z. B. aus einem Tarif- oder Betriebsvereinbarung). 0 = keine. Der Planer sieht einen „Veröffentlichen bis"-Hinweis und eine Warnung, sobald die Frist abgelaufen ist.

Nach der Aktivierung erscheint für Admins und Manager ein Eintrag Schichten und für jeden Mitarbeitenden ein Eintrag Meine Schichten.

b. Arbeitszeitmodell

Die täglichen Sollstunden jedes Nutzers ergeben sich aus seinem Arbeitszeitmodell:

  • Wöchentlich — feste/flexible Wochenstunden aus dem Arbeitszeitplan (Standard).
  • Schichtbasiert — die Sollstunden werden statt aus Wochenstunden aus dem veröffentlichten Dienstplan abgeleitet.
  • Erben — den Abteilungsstandard nutzen, dann auf wöchentlich zurückfallen.

Pro Nutzer unter Admin → Users einstellen oder als Abteilungsstandard unter Admin → Departments. Nur schichtbasierte Nutzer sind vom Dienstplan betroffen; wöchentliche Nutzer behalten ihren Plan.

c. Vorlagen & Dienstplan

Vorlagen sind wiederverwendbare Schichtdefinitionen (z. B. „Früh 06:00–14:00"), die unter Schichten angelegt werden. Jede hat einen Namen, Start- und Endzeit (liegt das Ende nicht nach dem Start, geht die Schicht über Mitternacht, z. B. 22:00–06:00), eine Pause in Minuten (wird vom Brutto abgezogen und ergibt die bezahlte Nettozeit), eine Farbe für das Raster und ein Aktiv-Kennzeichen. Schichten im gesetzlichen Nachtzeitfenster (23:00–06:00) werden für die ArbZG-Prüfungen automatisch erkannt.

Der Dienstplan ist ein Wochenraster aus Mitarbeitenden × Tagen. Weisen Sie pro Zelle eine Vorlage zu, fügen Sie eine optionale Notiz hinzu und nutzen Sie Vorwoche kopieren, um einen wiederkehrenden Plan zu übernehmen. Entwürfe sind für Mitarbeitende unsichtbar und beeinflussen die Sollstunden nicht. Wenn fertig, wählen Sie Veröffentlichen & benachrichtigen: Die Zuweisungen werden in Meine Schichten sichtbar, speisen die schichtbasierten Sollstunden, benachrichtigen betroffene Mitarbeitende (E-Mail und/oder Push, je nach Einstellung) und zeigen jedem Mitarbeitenden eine genaue Änderungsübersicht gegenüber der zuletzt veröffentlichten Version.

d. Tausch, offene Schichten & Verfügbarkeit

  • Schichttausch (Abgabe). Aus Meine Schichten gibt ein Mitarbeitender eine veröffentlichte Schicht ab; ein Kollege übernimmt sie und ein Manager/Admin genehmigt die Neuzuweisung (offen → übernommen → genehmigt oder abgelehnt/zurückgezogen). Nur ein genehmigter Tausch verschiebt die Zuweisung.
  • Offene Schichten. Ein Planer bietet einen nicht zugewiesenen Slot dem Pool an; Mitarbeitende bewerben sich und ein Manager genehmigt, wodurch er zu einer normalen Zuweisung wird (offen → übernommen → besetzt).
  • Verfügbarkeit. Mitarbeitende markieren Tage als Nicht verfügbar oder Bevorzugt (kein Eintrag = keine Präferenz). Wird jemand an einem als nicht verfügbar markierten Tag eingeteilt, kennzeichnet der Dienstplan einen Konflikt.

e. Mitarbeiteransicht, Kalender & Erinnerungen

Meine Schichten zeigt dem Mitarbeitenden den eigenen veröffentlichten Dienstplan als Woche oder Monat; er kann den Plan bestätigen („Ich habe meine Schichten gesehen") und von hier aus Verfügbarkeiten, Tausch und Bewerbungen auf offene Schichten verwalten.

Kalender-Abo. Mitarbeitende können einen Kalender-Feed aktivieren und die erzeugte iCalendar-URL (/shifts/feed/<token>) in jeder Kalender-App abonnieren; er aktualisiert sich automatisch, und beim Deaktivieren wird der Link ungültig.

Erinnerungen vor Schichtbeginn. Setzen Sie SHIFT_REMINDER_HOURS (siehe Schichtplanung unter den Umgebungsvariablen), um so viele Stunden vor Schichtbeginn eine Erinnerung zu senden — einmal pro Schicht, an Mitarbeitende, die die Push-Benachrichtigung „Schichtplan veröffentlicht oder geändert" aktiviert haben.

ArbZG-Audit. Klokk prüft Dienstpläne gegen das Arbeitszeitgesetz — Tages-/Wochenhöchstgrenzen, die 11-stündige Ruhezeit und Nachtarbeitsregeln — und die Ansicht Jährliches ArbZG-Audit bietet eine Compliance-Übersicht pro Mitarbeitenden über das ganze Jahr.

6. Erweiterungen

Erweiterungen sind externe Dienste, die über das API- & Erweiterungssystem von Klokk angebunden werden: eine scope-basierte, schreibgeschützte REST-API, ausgehende Webhooks und eingehende WebSocket-Verbindungen. Die Konfigurationsvariablen finden sich unterAPI & Erweiterungen oben; dieser Abschnitt behandelt den Ablauf in der App und die hauseigenen Erweiterungen.

a. Nutzung in der App

Ein Super-Admin verwaltet Integrationen unter Admin → API & Erweiterungen (/admin/extensions). Jede Integration bündelt einenAPI-Schlüssel (nur einmal angezeigt — sicher aufbewahren), die nutzbaren Scopes und einen Verbindungsmodus:

  • Nur API — die Erweiterung fragt die REST-API mit ihrem Schlüssel ab (/api/v1/status, /users, /clock/states, /time/entries, /shifts/events, /companies); begrenzt auf 60/min pro IP.
  • Webhooks — Klokk sendet bei Ein-/Ausstempeln und Abwesenheitsereignissen ausgehende HTTP-POSTs.
  • WebSocket — die Erweiterung öffnet eine dauerhafte eingehende Verbindung unter GET /api/v1/extension/connect.

Scopes (z. B. read:users, read:time_entries, read:companies) autorisieren jeden Schlüssel; vergeben Sie nur, was eine Erweiterung benötigt. Die öffentliche API ist schreibgeschützt. EXTENSIONS_ENABLED=false entfernt die Admin-Routen, den WebSocket-Endpunkt und alle Webhooks (die einfache REST-API bleibt verfügbar).

b. Klokk Anchor

Klokk Anchor ist ein Begleitdienst, der täglich einen manipulationssicheren Nachweis Ihrer Zeiterfassungsdaten in dieIOTA-Rebased-(Starfish-)Blockchain schreibt. Jedes Ereignis wird auf ein einseitiges SHA-256-Commitment reduziert und in einem Merkle-Baum zusammengefasst; nur die tägliche Merkle-Wurzel wird verankert, sodass keine personenbezogenen Daten in Richtung Chain gelangen. Optional wird ein vertrauenswürdiger Zeitstempel nach RFC 3161 ergänzt.

Voraussetzungen: ein laufendes Klokk mit EXTENSIONS_ENABLED=true; ein Klokk-API-Schlüssel mit den Scopes read:time_entries und read:companies; sowie zwei 32-Byte-Hex-Geheimnisse (eines für die Verschlüsselung im Ruhezustand, eines für das Hashing der Firmen-Token). Für das Mainnet eine finanzierte IOTA-Wallet (in der Anchor-Oberfläche erstellt); der Anchor-Smart-Contract von Klokk ist als Standard eingebaut.

Image: klokkme/anchor / ghcr.io/klokk-me/anchor (Tags stable, latest). PostgreSQL wird über DATABASE_URL unterstützt.

docker-compose.yml

services:
  klokk-anchor:
    image: klokkme/anchor:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:9090:9090"
    volumes:
      - anchor-data:/app/data
    environment:
      KLOKK_BASE_URL: "https://klokk.example.com"
      KLOKK_API_KEY: "klokk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      DATABASE_URL: "sqlite:/app/data/klokk-anchor.db"
      ENCRYPTION_KEY: "change-me-openssl-rand-hex-32"
      COMPANY_TOKEN_PEPPER: "change-me-openssl-rand-hex-32"
      IOTA_NETWORK: "testnet"
      TZ: "Europe/Berlin"
      TIMEZONE: "Europe/Berlin"

volumes:
  anchor-data:
Zuerst die Geheimnisse erzeugen: openssl rand -hex 32 zweimal für ENCRYPTION_KEY und COMPANY_TOKEN_PEPPER ausführen. Wird ENCRYPTION_KEY nach dem Anlegen von Wallets geändert, sind diese dauerhaft unlesbar.

Umgebungsvariablen

VariableStandardBeschreibung
KLOKK_BASE_URL ErforderlichBasis-URL Ihrer Klokk-Instanz.
KLOKK_API_KEY ErforderlichErweiterungs-API-Schlüssel mit read:time_entries + read:companies. Ein firmengebundener Schlüssel beschränkt den Anchor auf diese Firma. Geheim halten.
DATABASE_URLsqlite:data/klokk-anchor.dbSQLite-Pfad (sqlite:…) oder PostgreSQL-DSN (postgresql://…).
ENCRYPTION_KEY Erforderlich64-stelliger Hex-Wert (32 Byte). AES-256-GCM-Schlüssel für gespeicherte privaten Wallet-Schlüssel. openssl rand -hex 32.
COMPANY_TOKEN_PEPPER ErforderlichGeheimnis, das vor dem SHA-256-Hashing in die Firmen-Token eingemischt wird, sodass Firmen-IDs nicht aus On-Chain-Werten rückrechenbar sind.
IOTA_NETWORKtestnettestnet, mainnet oder localnet. IOTA_ANCHOR_PACKAGE verwendet standardmäßig das von Klokk bereitgestellte Package.
TIMEZONE / DAILY_BOOKING_TIMEUTC / 00:00IANA-Zeitzone und feste tägliche Buchungszeit (HH:MM) zum Verankern des Vortags.
ANCHOR_EMPTY_DAYStrueAuch an Tagen ohne Einträge einen Nachweis verankern (positiver Beleg „niemand hat gearbeitet"). Eine Transaktion pro Firma und leerem Tag.
TSA_URLOptionale RFC-3161-Zeitstempelstelle (kann ein qualifizierter eIDAS-QTSP sein). Best-Effort; blockiert das Verankern nie.
LEDGER_URLSKommagetrennte Klokk Ledger-URLs, um Nachweise bei der Verifizierung gegenzuprüfen — eine betreiberunabhängige vierte Prüfung.
ADMIN_PORT9090Port für die Web-Oberfläche und die REST-API (für Remote-Zugriff hinter einen Reverse-Proxy legen).

c. Klokk Ledger

Klokk Ledger ist ein unabhängiger Indexer- und Verifizierungsdienst. Er liest Klokk-Anchor-Nachweise aus dem öffentlichen IOTA-Ledger zurück, speichert sie und stellt eine schreibgeschützte Verifizierungs-API bereit — sodass jeder einen Nachweis prüfen kann, ohne dem Betreiber zu vertrauen, und selbst dann, wenn der Ledger-Knoten alte Transaktionen später entfernt. Er benötigt keinen API-Schlüssel und keine Geheimnisse; er liest nur öffentliche Daten und füllt beim ersten Lauf die vollständige Package-Historie automatisch nach.

Image: klokkme/ledger / ghcr.io/klokk-me/ledger (Tags stable, latest). SQLite ist reines Go (kein CGO); PostgreSQL optional.

docker-compose.yml

services:
  klokk-ledger:
    image: klokkme/ledger:stable
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - ledger-data:/app/data
    environment:
      IOTA_NETWORK: "mainnet"
      IOTA_ANCHOR_PACKAGE: "0x..."   # dasselbe Package, in das dein Anchor schreibt
      DB_DRIVER: "sqlite"
      DB_DSN: "data/klokk-ledger.db"
      POLL_INTERVAL: "60s"

volumes:
  ledger-data:

Umgebungsvariablen

VariableStandardBeschreibung
IOTA_ANCHOR_PACKAGE ErforderlichAdresse des zu indexierenden klokk_anchor-Move-Packages — dasselbe, in das Ihr Anchor schreibt.
IOTA_NETWORKtestnettestnet, mainnet oder devnet (wählt den Standard-GraphQL-Endpunkt; mit IOTA_GRAPHQL_URL überschreibbar).
DB_DRIVER / DB_DSNsqlite / data/…sqlite oder postgres, mit dem passenden Dateipfad bzw. DSN.
LISTEN_ADDR:8080Adresse, auf der die HTTP-API lauscht.
POLL_INTERVAL60sWie oft der Ledger nach neuen Nachweis-Ereignissen abgefragt wird (z. B. 30s, 5m).
ADDRESSESallOptionale kommagetrennte Anchor-Absenderadressen zum Indexieren. Leer = jeder Nachweis für das Package.

Verifizierungs-API

Alle Endpunkte sind offen verfügbar. GET /api/v1/verify/{tx}?root=<expected> liefert den unabhängig indexierten Nachweis und ob er der erwarteten Merkle-Wurzel entspricht — dieselbe Gegenprüfung, die Klokk Anchor über LEDGER_URLS durchführt.

EndpunktBeschreibung
GET /api/v1/statusNetzwerk, Package, Anzahl indexiert, Zeitpunkt der letzten Indexierung.
GET /api/v1/verify/{tx}Verifizierungsergebnis; mit ?root= gegen die indexierte Wurzel vergleichen.
GET /api/v1/proofs/{tx}Ein einzelner indexierter Nachweis anhand des Transaktions-Digests.
GET /api/v1/proofsNachweise für einen sender auflisten, mit Filtern company_token/period.
GET /api/v1/companies/{token}/proofsNachweise für ein Firmen-Token, optional nach Zeitraum.

7. Projektzeiterfassung

Mit der Projektzeiterfassung teilst du die Arbeitszeit, die dein Team ohnehin erfasst, auf Projekte, Kunden und Tätigkeiten auf — ohne zu ändern, wie gestempelt wird. Es ist dieselbe Arbeitszeit, nur segmentiert: Tages- und Wochensummen bleiben identisch, jedes Segment trägt lediglich ein Projekt und optional eine Tätigkeit (Fahrzeit / Vor Ort / allgemein). Standardmäßig aus und über zwei Berechtigungsebenen sowie eine Nutzerberechtigung für private Projekte gesteuert.

a. Aktivieren — Firma & Abteilungen

Zwei Schalter müssen zusammenpassen, bevor ein Nutzer die Projektzeiterfassung sieht:

  • Firma (Hauptschalter). Ein Super-Admin aktiviert Projektzeiterfassung pro Firma unter Admin → Firmen. Ist er aus, existieren keine Projekt-Oberflächen, -Routen oder -Stempelfunktionen.
  • Abteilung (Opt-in). Bei aktivem Firmenschalter wird jede Abteilung einzeln unter Admin → Abteilungen freigeschaltet (Projektzeit für diese Abteilung). Opt-in: eine neue Abteilung ist aus, bis sie freigeschaltet wird. Ein Nutzer mit Abteilung benötigt deren Freischaltung; Nutzer ohne Abteilung folgen dem Firmenschalter.

Sobald ein Nutzer qualifiziert ist, erscheint der Eintrag Projekte und das Stempel-Widget erhält Projekt-Bedienelemente. Upgrades bleiben funktionsfähig: Eine einmalige Migration schaltet die bestehenden Abteilungen jeder Firma frei, die Projekte bereits aktiviert hatte.

b. Berechtigung für private Projekte

Neben firmenweiten Projekten können Nutzer eigene private Projekte führen. Ob sie diese anlegen dürfen, steuert ein firmenweiter Standard (Admin → Firmen → Private Projekte standardmäßig erlauben), der pro Nutzer überschrieben werden kann (Admin → Nutzer: Firmenstandard / Erlauben / Sperren). Ist es gesperrt, wird das Formular „Neues privates Projekt" ausgeblendet und das Anlegen abgewiesen; bestehende private Projekte bleiben nutzbar.

c. Projekte & Sichtbarkeit

Admins verwalten Projekte unter Admin → Projekte (/admin/projects). Jedes Projekt hat einen Namen, optional Nummer und Kunde, eine Abteilung, ein Aktiv-Kennzeichen und eine Sichtbarkeit von Firma (für alle buchbar) oder Persönlich. Archivierte Projekte bleiben an historischen Einträgen, sind aber nicht mehr buchbar. Eigene private Projekte verwalten Nutzer unter Projekte (/projects).

d. Buchen, Umbuchen & Auswertung

Über das Stempel-Widget (oder die Projekte-Seite im eingestempelten Zustand) kann ein Mitarbeiter ein Projekt starten, zu einem anderen wechseln (das laufende Segment schließt, das nächste öffnet) oder die Projektarbeit stoppen und dabei eingestempelt bleiben. So entsteht eine Kette von Segmenten, die den Arbeitstag exakt ausfüllt; gestempelte, aber nicht zugeordnete Zeit erscheint unter Nicht zugewiesene Projektzeiten zur späteren Zuordnung.

Da ein Projektsegment nur Metadaten auf bereits genehmigter Arbeitszeit ist, löst das Umbuchen eines Segments auf ein anderes Projekt keine neue Genehmigung aus — die Stunden waren bereits gezählt. Admins erhalten eine projektbezogene Auswertung (/admin/projects/report, CSV-Export) mit Summen nach Projekt, Kunde und Zeitraum. Die öffentliche Erweiterungs-API liefert dieselben segmentierten Einträge über read:time_entries, und Klokk Anchor bindet jedes Segment in seinen täglichen Nachweis ein — so ist auch die Projektaufteilung manipulationssicher verankert.

8. Barrierefreiheit

Klokk ist nach WCAG 2.1/2.2 Stufe AA gebaut — der Konformitätsstufe hinter EN 301 549 sowie dem deutschen BFSG und der BITV 2.0. Barrierefreiheit gilt als Bau-Anforderung, nicht als Nachgedanke: Jede Ansicht ist tastaturbedienbar und für Screenreader beschriftet.

  • Volle Tastaturbedienung — jedes Element ist ohne Maus erreichbar und bedienbar, mit deutlich sichtbarem Fokusrahmen; ein „Zum Inhalt springen"-Link überspringt die Navigation.
  • Screenreader-Unterstützung — semantische Landmarken und Überschriften, beschriftete Icon-Buttons, ARIA-Live-Regionen für Seitenwechsel und Speicher-/Fehlermeldungen sowie der aktive Navigationspunkt via aria-current.
  • Dialoge — Modale sind echte role="dialog" mit gefangenem Fokus, Rückgabe beim Schließen und Schließen per Escape.
  • Standardmäßig lesbar — Textkontrast erfüllt das Minimum von 4,5:1 in hellem und dunklem Design, Layouts brechen bis zu kleinen Bildschirmen um, und nichts beruht allein auf Farbe.
  • Respektiert Einstellungen — berücksichtigt die System-Einstellung prefers-reduced-motion, und die Seitensprache ist deklariert, damit Screenreader Deutsch und Englisch korrekt aussprechen.