The app is used internally only and its settings page was German already. Mails, controller error messages (shown in the form), the settings section name and the mail sender are now written in German directly instead of going through IL10N without any translation files. Nextcloud's own mail footer is requested in German as well.
Deck Workflow-Automatisierung
Nextcloud-App für Nextcloud Hub Summer 26 (Server 35.x), die überfällige Karten der Deck-App automatisch von einem Stapel in einen anderen verschiebt und optional eine E-Mail-Benachrichtigung verschickt.
Ersetzt das früher genutzte eigenständige PHP-Cron-Skript durch eine vollwertige App mit Oberfläche in den persönlichen Einstellungen — jeder Nutzer kann dort seine eigenen Regeln ("Workflows") anlegen, ohne Admin-Rechte oder Server-Zugriff zu benötigen.
Funktionsumfang
Pro Workflow lässt sich konfigurieren:
-
Quell-Board und Quell-Stapel
-
Ziel-Stapel, in den alle überfälligen Karten des Quell-Stapels verschoben werden
-
E-Mail-Benachrichtigung über verschobene Karten, in drei Stufen:
- Keine E-Mail
- Nur an mich – an den Board-Eigentümer, unabhängig von seinen Deck-Einstellungen
- An Board-Mitglieder laut Deck-Einstellung – an alle, die das Board sehen dürfen (Eigentümer, freigegebene Nutzer, Mitglieder freigegebener Gruppen und Teams), gefiltert nach deren eigener Deck-Einstellung Benachrichtigungen für dieses Board: Alle Karten → immer, Zugewiesene Karten (Deck-Standard) → nur wenn man der Karte direkt oder über eine Gruppe/ein Team zugewiesen ist, Keine → nie. Der Eigentümer eines nicht geteilten Boards bekommt wie in Deck jede Karte, außer er hat Keine gewählt.
Pro Lauf des Hintergrundjobs bekommt jeder Empfänger höchstens eine Sammelmail mit allen für ihn verschobenen Karten.
Die App ist für den internen Einsatz gedacht und durchgehend deutschsprachig (Oberfläche, Fehlermeldungen, E-Mails). Es gibt keine Übersetzungsdateien.
Workflows lassen sich nur für Boards anlegen, deren Eigentümer man ist. Ein Workflow gehört dem jeweiligen Board-Eigentümer, nicht dem, der ihn angelegt hat: Wird ein Board in Deck übertragen, sieht und verwaltet ab sofort der neue Eigentümer seine Workflows, und der Hintergrundjob läuft in dessen Namen. Ein Nutzer kann beliebig viele Workflows anlegen, bearbeiten, deaktivieren oder löschen.
Architektur
- Keine HTTP/OCS-Aufrufe gegen Deck. Alles Lesen (Boards, Stapel, Karten) und das Verschieben von Karten läuft ausschließlich über Decks eigene interne PHP-Klassen (
OCA\Deck\Service\CardService,StackService,BoardService,OCA\Deck\Db\CardMapper, …), aufgelöst per Dependency Injection direkt im selben PHP-Prozess. Sämtlicher Deck-Zugriff ist inlib/Service/DeckIntegrationService.phpgebündelt. - Hintergrundjob statt Seitenaufruf.
lib/BackgroundJob/RunWorkflowsJob.phpist ein einfacherJobohne eigenes Intervall: Er läuft bei jedem Cron-Durchlauf von Nextcloud (üblicherweise alle 5 Minuten) und ruftlib/Service/WorkflowRunner.phpauf. - Rechte-Kontext je Nutzer. Ein Hintergrundjob hat standardmäßig keinen eingeloggten Nutzer, muss aber die Regeln mehrerer Nutzer in einem einzigen Lauf auswerten. Der
WorkflowRunner"verkörpert" deshalb für die Dauer der jeweiligen Workflows kurzzeitig den entsprechenden Besitzer. Dazu gehört mehr alsIUserSession::setUser(): Decks Berechtigungsprüfungen lesen die Session gar nicht, sondern eine Benutzer-ID, die beim Bau des Deck-Containers einmal pro Prozess eingefroren wird.DeckIntegrationService::beginUserContext()setzt diesen Wert für die Dauer der Verkörperung auf den Workflow-Besitzer und stellt ihn danach wieder her; schlägt das fehl, wird der Nutzer in diesem Lauf übersprungen, statt unter fremden Rechten zu arbeiten. - E-Mail läuft über Nextclouds eigenen
IMailer(nutzt also den in der Nextcloud-Administration hinterlegten Mailserver) und geht an die im Profil der jeweiligen Empfänger hinterlegte Adresse. Die Empfänger und ihre Deck-Einstellungen ermittelt die App ebenfalls über Decks interne Klassen bzw. die Nutzereinstellungdeck/board:<id>:notify-due.
Wichtiger Hinweis zu Decks internen Klassen
OCA\Deck\* ist keine dokumentierte, stabile öffentliche API von Deck (keine @since-Markierungen, keine offizielle Zusicherung von Abwärtskompatibilität). Diese App verwendet sie trotzdem bewusst direkt, wie es die Vorgabe verlangt — jeder Zugriff läuft defensiv abgesichert über DeckIntegrationService (Prüfung, ob Deck aktiviert ist, class_exists()-Checks, try/catch mit Logging statt Absturz). Nach größeren Deck-Updates lohnt sich ein Blick ins Nextcloud-Log, falls Workflows plötzlich nicht mehr greifen.
Installation
- App in
apps/workflow_deck_automationdes Nextcloud-Servers ablegen (oder über den Appstore-Build aus der CI, siehe unten). - In der Nextcloud-Administration unter Apps aktivieren.
- Die Deck-App muss installiert und für die jeweiligen Nutzer aktiviert sein.
- Sicherstellen, dass der Hintergrundjob-Modus auf Cron (empfohlen) steht, damit
RunWorkflowsJobregelmäßig läuft.
Benutzung
Jeder Nutzer findet die Einstellungen unter Persönliche Einstellungen → Deck Workflow-Automatisierung. Dort können neue Workflows angelegt, bestehende bearbeitet oder gelöscht werden. Die Dropdowns für Board und Stapel werden live aus Deck geladen. Zur Auswahl stehen nur aktive Boards, deren Eigentümer man ist — geteilte, archivierte und im Papierkorb liegende Boards sowie gelöschte Stapel blendet die App aus.
Gelöschte Boards und Stapel
Ein Workflow verweist per ID auf ein Board und zwei Stapel. Wird eines davon in Deck gelöscht, passiert Folgendes:
- Beim Speichern werden Board und Stapel geprüft; ein Workflow auf nicht mehr existierende Ziele lässt sich gar nicht erst anlegen.
- In der Übersicht wird ein betroffener Workflow rot markiert („Board nicht mehr vorhanden", „Quell-Stapel nicht mehr vorhanden" …).
- Im Hintergrundjob wird der Workflow automatisch deaktiviert und der Besitzer einmalig per E-Mail informiert — unabhängig von der E-Mail-Einstellung des Workflows, denn hier geht es nicht um verschobene Karten, sondern darum, dass die Automatisierung nicht mehr läuft. Danach bleibt es still: Ein deaktivierter Workflow wird nicht erneut ausgewertet.
Ist Deck vorübergehend nicht erreichbar, wird nicht deaktiviert — der Job überspringt den Workflow und versucht es beim nächsten Lauf erneut. Archivierte Boards lösen die Deaktivierung ebenfalls nicht aus, sie sind nur in den Auswahlfeldern ausgeblendet.
Ausführungstakt
Der Hintergrundjob hat kein eigenes Intervall und ist auch nicht konfigurierbar: Er läuft bei jedem Cron-Durchlauf von Nextcloud. Der Takt ist damit exakt der des System-Crons — üblicherweise alle 5 Minuten, bei einem häufiger eingerichteten Cron entsprechend öfter.
Bis einschließlich v0.1.0 gab es dafür die
config.php-Optionworkflow_deck_automation.interval. Sie ist entfallen und wird ignoriert; ein vorhandener Eintrag kann aus derconfig.phpentfernt werden.
Der Job läuft nur nachts bzw. gar nicht
Nextcloud merkt sich in der Spalte time_sensitive der Tabelle oc_jobs, ob ein Job zeitkritisch ist, und überspringt „unkritische" Jobs außerhalb des Wartungsfensters. JobList::setLastRun() setzt diese Spalte nur in eine Richtung — von „zeitkritisch" auf „unkritisch", nie zurück. Wer eine ältere Version dieser App installiert hatte (bis einschließlich v0.1.0 war der Job TIME_INSENSITIVE), hat diesen Stempel noch in der Datenbank. Er wird weder durch ein App-Update noch durch app:enable zurückgesetzt.
Symptom: Ist in der config.php ein maintenance_window_start gesetzt, läuft der Job nur in diesem 4-Stunden-Fenster und den Rest des Tages gar nicht.
Einmalig korrigieren:
UPDATE oc_jobs SET time_sensitive = 0
WHERE class = 'OCA\\WorkflowDeckAutomation\\BackgroundJob\\RunWorkflowsJob';
Ohne Datenbankzugriff geht es auch über occ, indem der Job gelöscht und durch Aus-/Einschalten der App neu registriert wird:
php occ background-job:list --class 'OCA\WorkflowDeckAutomation\BackgroundJob\RunWorkflowsJob'
php occ background-job:delete <id>
php occ app:disable workflow_deck_automation
php occ app:enable workflow_deck_automation
Neuinstallationen sind nicht betroffen.
Entwicklung
Voraussetzungen: PHP 8.2+, Composer, Node.js 24+, npm 11+.
composer install
npm install
npm run build # einmaliger Produktions-Build
npm run watch # Entwicklung mit automatischem Rebuild
Tests & Linting
composer run lint # php -l über lib/ und tests/
composer run cs:check # nextcloud/coding-standard (php-cs-fixer)
composer run test:unit # PHPUnit — reine Logik (Fälligkeitsprüfung), benötigt keine Deck-Installation
Ein echter End-to-End-Test (Karte anlegen, Workflow konfigurieren, Hintergrundjob auslösen, Verschiebung + Mail prüfen) lässt sich nur gegen eine echte Nextcloud-34-Instanz mit installierter Deck-App durchführen, z. B. per:
# Job-ID und letzten Lauf anzeigen
php occ background-job:list --class 'OCA\WorkflowDeckAutomation\BackgroundJob\RunWorkflowsJob'
# Sofort ausführen, ohne auf den nächsten Cron-Durchlauf zu warten
php occ background-job:execute <id> --force-execute
# Oder dauerhaft als Worker laufen lassen (Argument ist die Job-Klasse, keine App-ID)
php occ background-job:worker 'OCA\WorkflowDeckAutomation\BackgroundJob\RunWorkflowsJob'
Release-Paket bauen
make appstore
Erzeugt build/artifacts/appstore/workflow_deck_automation.tar.gz.
CI (Gitea Actions)
| Workflow | Zweck |
|---|---|
lint-php.yml |
php -l über eine PHP-8.2–8.4-Matrix |
lint-info-xml.yml |
validiert appinfo/info.xml gegen das Appstore-XML-Schema |
phpunit.yml |
führt die PHPUnit-Tests aus (SQLite/rein logisch, kein DB-Service nötig) |
build-main.yml |
baut Frontend + Appstore-Archiv und veröffentlicht es als Release-Asset — bei Push auf main als rollendes Pre-Release latest-main, bei Push eines v*-Tags als reguläres Release |
Datenmodell
Workflows werden in der Tabelle wfda_workflows gespeichert (siehe lib/Migration/Version1000Date20260813120000.php): eine Zeile pro Workflow, mit Board-/Stapel-IDs, user_id (der Board-Eigentümer, in dessen Namen der Job läuft — wird bei jedem Lauf aus Deck aktualisiert) sowie enabled/notify_mode/last_run. Die früheren Filter-Spalten filter_user_ids/filter_label_ids entfernt Version1001Date20260930120000. Version1002Date20261001120000 ersetzt das frühere Ja/Nein-Feld notify_email durch notify_mode (off/owner/board; gesetztes Häkchen → owner), Version1003Date20261001120100 entfernt die alte Spalte.
Lizenz
AGPL-3.0-or-later