{"id":21330606,"url":"https://github.com/friendsofredaxo/collaborate","last_synced_at":"2025-10-11T03:20:26.113Z","repository":{"id":61355047,"uuid":"543515713","full_name":"FriendsOfREDAXO/collaborate","owner":"FriendsOfREDAXO","description":"Addon für paralleles Arbeiten im Backend \u0026 mehr","archived":false,"fork":false,"pushed_at":"2024-11-06T20:33:57.000Z","size":1724,"stargazers_count":15,"open_issues_count":2,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-07-27T06:05:23.227Z","etag":null,"topics":["collaboration","data-consistency","redaxo","redaxo-addon","teamwork","websocket"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FriendsOfREDAXO.png","metadata":{"files":{"readme":"README.de.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-09-30T09:05:02.000Z","updated_at":"2023-07-12T13:35:15.000Z","dependencies_parsed_at":"2024-11-22T00:05:41.501Z","dependency_job_id":null,"html_url":"https://github.com/FriendsOfREDAXO/collaborate","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/FriendsOfREDAXO/collaborate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FriendsOfREDAXO%2Fcollaborate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FriendsOfREDAXO%2Fcollaborate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FriendsOfREDAXO%2Fcollaborate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FriendsOfREDAXO%2Fcollaborate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FriendsOfREDAXO","download_url":"https://codeload.github.com/FriendsOfREDAXO/collaborate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FriendsOfREDAXO%2Fcollaborate/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006098,"owners_count":26084026,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collaboration","data-consistency","redaxo","redaxo-addon","teamwork","websocket"],"created_at":"2024-11-21T22:22:59.514Z","updated_at":"2025-10-11T03:20:26.096Z","avatar_url":"https://github.com/FriendsOfREDAXO.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Collaborate - Zusammenarbeit im Backend \u0026 mehr\n\n![Screenshot](https://github.com/FriendsOfREDAXO/collaborate/blob/main/assets/collaborate.png)\n\nCollaborate ist ein REDAXO Addon, welches primär entwickelt wurde, um **kollisionsfreie, parallele Zusammenarbeit** im Backend zu ermöglichen.\nDer Kern des AddOns ist ein unabhängig von der REDAXO-Instanz (als Website) arbeitender Dienst, der permanent läuft und einen **Websocket Server**\nzur Verfügung stellt. Plugins liefern dann die eigentlichen Features und können via Callbacks und Event-Handler sowohl server-seitig (PHP)\nals auch client-seitig (JS) auf Aktionen von Backend- und Front-Nutzern reagieren.\n\n## Installation\n\nDie folgende Installationsanweisung fokussiert sich auf Anpassungen am Webserver und setzt in diesem Kontext das Vorhandensein eines gültigen **Let's\nEncrypt**-Zertifikats voraus. Die unten stehenden Code-Schnipsel und Konfigurationsempfehlungen sind nicht direkt für die Nutzung mit anderen SSL-Zertifikaten\nanwendbar.\n\n### Schritt 1: Vorbereitung des Webservers\n\n**Voraussetzungen zusammengefasst**\n* Server-Zugriff inkl. Webserver-Konfigurationsdateien\n* Server-Restart möglich\n* idealerweise root-Zugriff oder Managed-Server \u003e dann den Betreiber die Anpassungen durchführen lassen\n* Installation von `mod_proxy` (bei Apache)\n\nFür die Nutzung des AddOns sind **Anpassungen an der Server-Konfiguration notwendig**. Bei geteilten Hosting-Paketen (_Shared Hosting_) wird man in der Regel\nvom Betreiber keine Anpassungen an seiner Server-Konfigurartion erwarten können, da diese dann immer mehrere Kunden auf diesem Server betreffen\nund das wiederum zu weiteren offenen Flnken führt, die Administratoren aus Sicherheitsgründen gern vermeiden.\n\nSollte die Website, für die man Collaborate unter REDAXO betreiben möchte auf einem **Managed Server** liegen, müsste der Support des Server-Betreibers\nnormalerweise die notwendigen Anpassungen erledigen können. Dort sollte dann kommuniziert werden, dass es um Websockets via SSL (wss-Protokoll) für Domain X geht\nund alles über Port P laufen soll.\n\nDen Port findet man übrigens in der `package.yml` im AddOn-Basisverzeichnis. Dort steht unter `websocket-server-port` der Port,\nunter dem das Collaborate-Websocket dann laufen wird. Dieser ist per default auf **6789** gesetzt und wird deshalb in nachfolgenden Konfigurations-Schnipseln auch so eingesetzt.\nMöchte man diesen ändern, müsste diese Änderung in der Datei erfolgen und anschließend das AddOn re-installiert werden. Falls zu diesem Zeitpunkt schon die Server-Application lief,\nmüsste diese (einzeln oder via [Service](#schritt-2-service-datei-einrichten)) ebenfalls neu gestartet werden, um die Port-Anpassung zu berücksichtigen.\n\nAbsolut notwendig für den Betrieb des AddOns ist das Vorhandensein von `mod_proxy`.\n\n#### Apache\n\nDie nachfolgende Basis-Konfiguration faktisch ein Server-internes Routing der Websocket-Verbindungen auf reguläre Verbindungen, die dann über Portmapping\ndem Collaborate-Application-Prozess zur Verfügung gestellt werden. Der Rückweg von der Application zum Client erfolgt ebenfalls hierüber.\n\nMehr Infos dazu hier: https://letsencrypt.org/de/docs/challenge-types/\n\n```\n\u003cIfModule mod_proxy.c\u003e\n    ProxyPass /wss ws://0.0.0.0:6789/\n    ProxyPassReverse /wss ws://0.0.0.0:6789/\n\u003c/IfModule\u003e\n```\n\n#### nginx\n\n_TODO_\n\n### Schritt 2: Service-Datei einrichten\n\nBei der Installation des AddOns wird im Pfad `[...]/redaxo/src/addons/collaborate/conf/collaborate.service` eine .service-Datei erstellt und bereits\nmit den richtigen Pfaden für den aktuellen Server vorausgefüllt. Dort stehen auch oben in den Kommentaren noch einmal alle wichtigen Kommandos für die\nnachfolgenden Schritte; ebenfalls vorausgefüllt mit den korrekten Pfaden und direkt via Copy-and-paste einsetzbar.\n\nMan sollte beachten, dass folgende Kommandos als **root-User** ausgeführt werden sollten! \n\n**2.1 Sym-Link erstellen**\n\nMit nachfolgendem Kommando wird ein Sym-Link der Collaborate Service-Konfiguration in der Liste der System-Dienste ergänzt.\n\n`\u003e sudo ln -s [...]redaxo/src/addons/collaborate/conf/collaborate.service /etc/systemd/system/collaborate_websocket_[NAME].service`\n\n**2.2 Dienst-Befehle** \n\n* Websocket-Dienst (und damit die Server-Application) **starten**:\u003cbr /\u003e\n`\u003e sudo systemctl start collaborate_websocket_[NAME].service`\u003cbr /\u003e\n* Websocket-Dienst **stoppen**:\u003cbr /\u003e\n`\u003e sudo systemctl stop collaborate_websocket_[NAME].service`\u003cbr /\u003e\n* Websocket-Dienst **Status-Abfrage**:\u003cbr /\u003e\n`\u003e sudo systemctl status collaborate_websocket_[NAME].service`\n\n### Schritt 3: Anpassungen in REDAXO-Templates für Plugins mit Frontend-Features\n\nDas Kern-AddOn fokussiert sich auf Zusammenarbeit im Backend und setzt dafür Sicherheitsroutinen ein, die dafür sorgen, dass nur\nVerbindungen von Backend-Nutzern zugelassen werden. Dennoch ist es möglich, Plugins so zu entwickeln, dass Up- und/oder Down-Stream\nWebsocket-Verbindungen aus dem Frontend zulassen (mehr dazu in [Plugin-Entwicklung](#plugin-entwicklung)).\n\nDiese AddOns benötigen in der Regel eigene JavaScript-Dateien (und ggf. auch eigene CSS-Dateien). Um diese im Frontend zu laden, sind folgende\n2 Anpassungen notwendig:\n1. In den Templates, in denen Collaborate im Frontend eingebunden werden soll, muss der Platzhalter `REX_COLLABORATE_FRONTEND[]` im\n`\u003chead\u003e`-Bereich eingebunden werden. Dieser sorgt für das Laden und Instanziieren der zentralen Collaborate-Klasse und lädt des Weiteren\ndie Frontend-Ressourcen aktivierter Plugins.\n2. Plugins benötigen im Ordner `/assets/js/` eine Datei mit dem Namensschema `collaborate.plugin.[PLGUINNAME].frontend.js`.\nZur automatischen Einbindung einer CSS-Datei muss diese in `/assets/css/` mit dem Namensschema `collaborate.plugin.[PLGUINNAME].frontend.css`\nangelegt werden.\n\n...\n\n## AddOn-Features  \n\n* Multi-Tab- bzw. Fenster-Erkennung via Tab IDs\n  * 1 Tab/Fenster = 1 registrierte Client-Verbindung\n  * vor dem Broadcasting werden mehrere Verbindungen desselben Nutzers zusammengeführt \n* Header-Bar-Toolbox im REDAXO-Backend mit Indikator, ob der Websocket-Server läuft bzw. der Client dorthin eine Verbindung aufbauen kann\n  (benötigt Berechtigung `collaborate[]`)\n  * Auto-Reconnect nach 60sek, falls der Server offline ist\n  * wenn offline wird ein Button zum manuellen Reconnect sichtbar\n  * Anzeige der Summe aller anderen aktiven Backend-Nutzer (eigene Verbindung wird dabei nicht mitgezählt!)\n* Einzelrechte des Haupt-AddOns erweitern die Toolbox um mehr Funktionen:\n  * `collaborate[users]` - Toolbox ist klickbar und zeigt die Namen aller anderen aktuell eingeloggten Nutzer und seit wann diese online sind\n  * `collaborate[user_locations]` - zeigt zusätzlich an, welche Nutzer in welchen Sektionen (1-n) unterwegs sind und auch wie viele Tabs/Fenster sie geöffnet haben\n* trotz Fokus auf Backend-Tools Einbindung im Frontend möglich und via Plugins steuerbar\n* Websockets via SSL (wss-Protokoll)\n\n## Identity Check für Backend-Aktionen\n\nDer Collaborate-Server wird unter der Prämisse entwickelt, dass Änderungen auf CMS-Ebene möglichst keinen Neustart des Websocket-Dienstes erfordern.\nDer Websocket-Server führt deshalb in regelmäßigen Abständen Prüfungen der Nutzerdatenbank (`rex_user`) durch und speichert das aktuelle Abbild\nin einer eigenen Datenstruktur. Die Wiederholung dieses Checkups zur Laufzeit (\"Loop\" genannt) sorgt dafür, dass der Server mit leichter zeitlicher Verzögerung\nneu hinzugekommene, gelöschte, deaktivierte oder hinsichtlich ihrer Rollen und Rechte veränderte Nutzer registriert und im weiteren Programmablauf der Application\ndarauf reagieren kann.\n\nFür eine grundlegende Identifikation von aus dem Backend-Client eingehenden Anfragen werden die Parameter `user` (Login-Name des Backend-Nutzers)\nund ein Feld `userhash` übermittelt, welches anhand bestimmter Daten des Accounts generiert wird. Auf der Server-Seite wird beim Start und bei der zyklischen\nÜberprüfung der User-Accounts derselbe Hash erzeugt und abgegleichen. Anfragen\n\n## Logging \u0026 Datenschutz\n\nDie Collaborate Application und ggf. auch eingebundene Plugins schreiben zur Überprüfung des korrekten Programmablaufs regelmäßig Ausgaben mittels `echo`.\nDie o.g. Standard-Implementierung als Dienst leitet diese Ausgaben in eine Log-Datei unter `[...]/redaxo/data/addons/collaborate/collaborate.log` um. Dateien\nim `/data/`-Bereich sind vor Direktaufrufen im Browser geschützt. Ebenfalls sorgt die o.g. interne Umleitung der Websocket-Verbindungen dafür, dass\nim Log stets `127.0.0.1` als IP-Adresse für eingehende Verbindungen erscheint, wodurch Restriktionen\n\n## Plugin-Entwicklung\n\nCollaborate stellt im Kern hauptsächlich eine **Server-Application (PHP)** und zugehörige **Client-Klassen (JS)** bereit.\nWegen des Fokus auf Zusammenarbeit von Backend-Nutzern ist die Verwaltung derer Verbindungen und Datenpakete bereits integriert.\nDas AddOn selbst liefert dabei nur minimale Features für die Nutzung im REDAXO Backend (siehe Feature-Liste).\n\nGeplant und gewünscht ist die Entwicklung von Plugins, die sowohl Frontend- als auch Backend-Features liefern können und sich mittels\nRegistrierung von Event-Handlern an die Prozesse der Application _\"anhängen\"_ können. Verbundene Clients können vor der\nweiteren Verarbeitung im Hauptprozess manipuliert oder Verarbeitungsschritte abgebrochen oder einkürzt werden.\n\n### package.yml\n\nIn der package.yml legt man für Up- und Downstream separat fest, ob diese das Backend, das Frontend oder beides betreffen. Bei der Installation des\nPlugins werden diese Flags in die Plugin-Config geschrieben und an anderer Stelle berücksichtigt. U.a. werden dann durch eine REX_VAR\n(siehe [hier](#schritt-3-anpassungen-in-redaxo-templates-fr-plugins-mit-frontend-features) Ressourcen von Frontend-scoped Plugins und durch die\nboot-Routine des Haupt-AddOns die von Backend-scoped Plugins automatisch eingebunden. Wichtig dafür ist eine konsistente Namensgebung in den\nPlugin-Assets:\n\n* **Frontend-Ressourcen** sind nach dem Schema `collaborate.plugin.PLUGINNAME.frontend.js/css` zu benennen\n* **Backend-Ressourcen** sind nach dem Schema `collaborate.plugin.PLUGINNAME.backend.js/css` zu benennen\n\nDie Konfiguration der package.yml selbst ist dann wie folgt vorzunehmen:\n\n```\ndefault_config:\n  # defines scopes for websocket up- and down streams\n  # 2 = frontend \u0026 backend\n  # 1 = frontend\n  # 0 = backend\n  # -1 = no automatic embedding\n  upstream_scope: 1\n  downstream_scope: 0\n```\n\n### Server\n\nIm `lib`-Ordner des Plugin sollte die Klasse des Plugins liegen. Diese muss von der abstrakten Klasse `CollaboratePlugin` erben, um beim Einlesen\ndurch die Application berücksichtigt zu werden. Diese Klasse kann mit vordefinierten Methoden dann auf bestimmte Events, die die Application bei\nbestimmten Programmprozessen auslöst, reagieren.\n\nEin Beispiel für die Entwicklung eines Plugins namens `\"test\"`:\n```php\nclass CollaboratePluginTest extends CollaboratePlugin {\n    /**\n    * do something with incoming messages (after successful backend user verification process!)\n    * @param $data\n    * @param ConnectionInterface $client\n    */\n    public function onMessage(\u0026$data, ConnectionInterface \u0026$client) {\n        // Zwischenspeichern aller aktuell registrierten Backend-Verbindungen\n        // ACHTUNG: Ein und selbe Backend-User kann mehrere Tabs/Fenster geöffnet haben \u003e jedes Tab/Fenster ist eine eigene Verbindung\n        $clients = $this-\u003eapp-\u003egetClients();\n\n        // $data repräsentiert die JSON Daten, die der Nutzer mit der Verbindung $client\n        // mit der Event-auslösendes Nachricht versendet hat (aus dem Browser heraus)\n        if(count($clients) \u003e 1 \u0026\u0026 $data-\u003etype == 'PAGE' \u0026\u0026 isset($data-\u003epage-\u003epath) \u0026\u0026 $data-\u003epage-\u003epath == \"templates\") {\n            foreach ($clients as $hash =\u003e $c) {\n                // aufrufender Benutzer wird ignoriert \u003e muss nicht über seine eigene Aktion informiert werden\n                if (!is_null($client) \u0026\u0026 $c['user'] == $data-\u003euser) {\n                    continue;\n                }\n\n                // Log-Eintrag schreiben\n                CollaborateApplication::echo(sprintf(\n                    \"test: Der Benutzer '%s' (resID %s) wird über den Besuch der Seite 'Templates' durch Benutzer (resID %s) informiert\",\n                    $c['user'],\n                    $c['connection']-\u003eresourceId,\n                    $client-\u003eresourceId\n                ));\n            }\n        }\n    }\n}\n```\n\nHier wird auf `onMessage` reagiert und lediglich ein Log-Eintrag generiert, wenn ein Benutzer $client die Backend-Seite 'Templates' aufruft.\nÜber das Manipulieren der $data-Variablen kann je nach Trigger-Punkt der weitere Programmablauf in der Main Application manipuliert\n(ggf. gestoppt) werden. Da Collaborate mit 3 Plugins ausgeliefert wird, u.a. `viewcounter` mit einem Handling für Frontend-Verbindungen, gibt\nes bereits einige Code-Schnipsel, die auch als Vorlage für eigene Entwicklungen dienen sollen.\n\n### Client\n\n_TODO_\n\n## Lizenz\n\nCollaborate ist unter der [MIT Lizenz](LICENSE.md) lizensiert.\n\n## Changelog\n\nsiehe [CHANGELOG.md](https://github.com/FriendsOfREDAXO/collaborate/blob/master/CHANGELOG.md)\n\n## Autor\n\n**Friends Of REDAXO**\n\n* https://www.redaxo.org\n* https://github.com/FriendsOfREDAXO\n\n**Projekt-Lead**\n\n[Peter Schulze | Bitshifters](https://github.com/bitshiftersgmbh)\n\n## Credits\n\nCollaborate basiert auf [Ratchet](https://github.com/ratchetphp/Ratchet) von [Chris Boden](https://github.com/cboden)\n\n----\n\n## TODOs\n\n* sinnloses Zustellen an verschiedene Connections desselben Clients (bei 3 offenen Tabs 2 unnötige Messages, weil für jedes Tab\n  ein weiterer Messageblock generiert wird \u003e Bug)\n* Test, ob dynamisches Einbinden von aktualisierten Plugin-Files oder neu hinzu gekommenen Plugins wirklich funktioniert\n* Beim zyklischen Plugin-Check deaktivierte/deinstallierte/verwaiste Plugins entfernen\n* Plugin-Vorlage: `mixed` konsequent durch `?object` ersetzen, vorher prüfen, wie stabil das ist\n* `downstream_scope` und `upstream_scope` Flags in package.yml korrekt und fertig implementieren (auto-include im Backend via boot.php)\n* `yform`-Plugin:\n  * Kollisionen serverseitig vermeiden (First come first served)\n* Doku für AddOn generell verbessern + für Plugins überhaupt erst schreiben \n* ggf. zentrales Object für FE-Verbindungen um bei mehreren FE-Plugins keine unnötige Redundanz zu erzeugen\n  * evtl. eigenes Log-File für FE Connections oder aber FE-Connections gar nicht loggen (erschwert allerdings Debugging sehr!)\n* `structure`\n  * Sperre pro clang (nicht generell über alle Sprachen) \n* `structure` + `yform` Plugins:\n  * wenn in Detailansicht geblockt \u003e nach Wiederfreigabe Seite neu laden, um auf aktuellem Stand zu sein\n* `viewcounter`\n  * Handling für verwaiste Frontend-Connections einbauen \u003e created Timestamp ergänzen und globale Ablaufzeit festlegen\n  * evtl. Flag/Methode für das Resetten aller FE-Verbindungen einbauen (über Easter-Egg oder Console aufrufbar) \u003e cleart FE Client Stack\n    auf Serverseite und löscht alle Bubbles in structure View (Clientseite)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriendsofredaxo%2Fcollaborate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffriendsofredaxo%2Fcollaborate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffriendsofredaxo%2Fcollaborate/lists"}