Flux — Zeitbuchung auf JIRA-Tickets
APP·November 2025

Flux — Zeitbuchung auf JIRA-Tickets

Aufwand pro Ticket erfassen, ohne die App überhaupt zu öffnen: ein laufender Timer im Dynamic Island, ein Tap im Widget, und die Zeit landet als Worklog in JIRA

PROJEKT

Flux
Zeitbuchung auf JIRA-Tickets

TECHNOLOGIEN

SwiftSwiftUIiOSSwiftDataLive ActivitiesWidgetKitJIRA REST APIKeychain

Herausforderung

Aufwandsbuchung in JIRA ist lästig. Wer projektbezogen arbeitet, soll die Zeit pro Ticket festhalten, aber die Weboberfläche dafür ist zäh, und am Handy erst recht. In der Praxis wird deshalb geschätzt und nachgetragen, statt sauber gemessen.

Flux dreht das um: ein Timer, der so beiläufig läuft wie eine Stoppuhr, sichtbar auf dem Lock-Screen, gestartet mit einem Tap, und dessen Ergebnis am Ende als Worklog im richtigen Ticket landet. Kein Kontextwechsel, kein Nachtragen.

Damit das trägt, mussten mehrere Dinge zusammenkommen:

  • Der laufende Timer muss präsent sein, ohne im Weg zu stehen: auf dem Lock-Screen und im Dynamic Island, nicht in einer App, die man erst öffnet
  • Das passende Ticket muss in Sekunden gefunden sein, aus einem Suchfeld heraus, ohne JQL zu tippen
  • Die erfasste Zeit muss verlässlich als JIRA-Worklog ankommen, auch wenn zwischendurch die Verbindung wegbricht
  • Mehrere JIRA-Instanzen (Cloud wie On-Premise) müssen parallel nutzbar sein, jede mit eigenen Zugangsdaten

Lösung

Flux ist eine native SwiftUI-App mit SwiftData-Persistenz, einem zentralen Timer-Service als Single Source of Truth und einer Widget-Extension, die denselben Zustand teilt. Vier Bausteine tragen das Produkt.

Der Timer lebt außerhalb der App

Sobald ein Timer läuft, blendet Flux eine Live Activity ein: auf dem Lock-Screen als persistentes Banner, auf neueren iPhones als Dynamic-Island-Capsule mit Compact-, Expanded- und Minimal-Modus. Möglich wird das durch einen Timer-Service, der als einzige Wahrheitsquelle den laufenden Eintrag im Speicher hält, jede Änderung über SwiftData persistiert und Updates gleichzeitig an Widget und Live Activity schickt. Der Zustand wird über eine geteilte App-Group zwischen App und Extension abgeglichen, inklusive Reconciliation, falls beide Seiten auseinanderlaufen.

Ticket finden ohne JQL

Die Ticket-Suche sieht aus wie ein simples Textfeld, dahinter läuft aber eine dreistufige Pipeline. Ein Parser klassifiziert die Eingabe (Ticket-Key, Freitext, Filter), ein Orchestrator baut daraus die passende JQL-Abfrage an die JIRA-API, und ein Ranker sortiert die Treffer client-seitig nach Relevanz. So tippt man „bug login“ oder direkt einen Ticket-Key und bekommt in Sekunden das Richtige, ohne die Abfragesprache zu kennen.

Verlässlich zurück nach JIRA

Am Ende schiebt Flux jeden lokalen Zeit-Eintrag als Worklog an die JIRA-REST-API. Die Buchung ist bewusst entkoppelt vom Messen: Erfasst wird immer lokal in SwiftData, der Sync ist ein eigener Schritt, der gezielt die noch offenen, dem aktiven Account zugeordneten Einträge herausfiltert und pusht. Bricht die Verbindung weg, bleibt der Eintrag lokal erhalten und geht später raus, statt verloren zu sein.

Mehrere Instanzen, ein Gerät

Flux verwaltet beliebig viele JIRA-Accounts parallel, Atlassian-Cloud über die Subdomain oder On-Premise über die volle Server-URL, mit API-Token oder Passwort je nach Server-Typ. Jeder Account bringt eigene Zugangsdaten (im Keychain), ein eigenes Farb-Theme und seine eigenen Zeiterfassungen mit. Ein durchdachtes Onboarding führt neue Nutzer Schritt für Schritt an genau diese Konzepte heran.

Code-Beispiele

Ergebnisse

Flux ist als Version 1.0 fertiggestellt und im Einsatz. Aus lästiger Nachtragerei wurde ein beiläufiger Timer, der die Zeit dorthin bringt, wo sie hingehört:

  • Laufender Timer als Live Activity auf Lock-Screen und Dynamic Island, plus Home-Screen-Widget
  • Zeit-Einträge landen als echte JIRA-Worklogs am jeweiligen Ticket, offline-tolerant gepusht
  • Ticket-Suche über eine Parser-JQL-Ranker-Pipeline, ohne dass der Nutzer JQL kennt
  • Multi-Account für Cloud und On-Premise, Zugangsdaten sicher im Keychain, Theme pro Account
  • Native SwiftData-Persistenz, geteilter Widget-Zustand über App-Group mit Reconciliation, zweisprachig

Der Reiz lag im iOS-Handwerk an der Oberfläche: einen Timer so tief in Lock-Screen, Dynamic Island und Widget zu verankern, dass die eigentliche App fast überflüssig wird, und dahinter trotzdem eine saubere, offline-taugliche Sync-Schicht zu JIRA zu halten.