From 8ed33d9d7d786af413dd7d522a14d77cc8284a10 Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Mon, 6 Oct 2025 14:18:50 +0200
Subject: [PATCH] groupware: improve instructions in DEVELOPER.md
---
services/groupware/DEVELOPER.md | 62 ++++++++++++++++++++++++++-------
1 file changed, 49 insertions(+), 13 deletions(-)
diff --git a/services/groupware/DEVELOPER.md b/services/groupware/DEVELOPER.md
index 523b208ba2..d0dee5e1d4 100644
--- a/services/groupware/DEVELOPER.md
+++ b/services/groupware/DEVELOPER.md
@@ -4,7 +4,7 @@ The Groupware component of OpenCloud
* is implemented as yet another microservice within the OpenCloud framework (see `./services/groupware/`)
* is essentially providing a REST API to the OpenCloud UI clients (web, mobile) that is high-level and adapted to the needs of the UIs
-* the implementation of that REST API turns those high-level APIs into lower-level [JMAP](https://jmap.io/) API calls to [Stalwart, the JMAP mail server](https://stalw.art/), using our own JMAP client library in `./pkg/jmap/`
+* the implementation of that REST API turns those high-level APIs into lower-level [JMAP](https://jmap.io/) API calls to [Stalwart, the JMAP mail server](https://stalw.art/), using our own JMAP client library in `./pkg/jmap/` with a couple of additional RFCs used by JMAP in `./pkg/jscalendar` and `./pkg/jscontact`
# Repository
@@ -36,7 +36,7 @@ Those scripts have the following prerequisites:
# Running
-Since we require having a Stalwart container running at the very least, the preferred way of running OpenCloud and its adjacent services for developing the Groupware component is by using the `opencloud_full` Docker Compose setup.
+Since we require having a Stalwart container running at the very least, the preferred way of running OpenCloud and its adjacent services for developing the Groupware component is by using the `opencloud_full` Docker Compose setup in `$OCDIR/devtools/deployments/opencloud_full`.
## Configuration
@@ -49,25 +49,29 @@ Make sure to have the following entries in your `/etc/hosts`:
```text
127.0.0.1 cloud.opencloud.test
127.0.0.1 keycloak.opencloud.test
-127.0.0.1 collabora.opencloud.test
127.0.0.1 wopiserver.opencloud.test
127.0.0.1 mail.opencloud.test
127.0.0.1 collabora.opencloud.test
-127.0.0.1 stalwart.opencloud.test
127.0.0.1 traefik.opencloud.test
+127.0.0.1 stalwart.opencloud.test
```
Alternatively, use the following shell snippet to extract it in a more automated fashion:
```bash
-cd "$OCDIR/opencloud/devtools/deployments/examples/opencloud_full/"
+cd "$OCDIR/opencloud/devtools/deployments/opencloud_full/"
-perl -ne 'if (/^([A-Z][A-Z0-9]+)_DOMAIN=(.*)$/) { print length($2) < 1 ? lc($1).".opencloud.test" : $2,"\n"}' <.env|sort|while read n; do grep -w -q "$n" /etc/hosts && echo -e "\e[32;4mexists :\e[0m $n: \e[32m$(grep -w $n /etc/hosts)\e[0m">&2 || { echo -e "\e[33;4mmissing:\e[0m ${n}" >&2; echo -e "127.0.0.1\t${n}";}; done | sudo tee -a /etc/hosts
+perl -ne 'if (/^([A-Z][A-Z0-9]+)_DOMAIN=(.*)$/) { print length($2) < 1 ? lc($1).".opencloud.test" : $2,"\n"}' <.env\
+|sort|while read n; do\
+grep -w -q "$n" /etc/hosts && echo -e "\e[32;4mexists :\e[0m $n: \e[32m$(grep -w $n /etc/hosts)\e[0m">&2 ||\
+{ echo -e "\e[33;4mmissing:\e[0m ${n}" >&2; echo -e "127.0.0.1\t${n}";};\
+done \
+| sudo tee -a /etc/hosts
```
### Compose
-It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtools/deployments/examples/opencloud_full/.env`, making the following changes:
+It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtools/deployments/opencloud_full/.env`, making the following changes (make sure to check out [the shell command-line that automates all of that, below](#automate-env-setup)):
* change the container image to `opencloudeu/opencloud:dev`:
```diff
@@ -121,10 +125,11 @@ It first needs to be tuned a little, and for that, edit `$OCDIR/opencloud/devtoo
+#EXTERNALSITES=:web_extensions/externalsites.yml
```
+
All those changes above can be automated with the following script:
```bash
-cd "$OCDIR/opencloud/devtools/deployments/examples/openclouf_full/"
+cd "$OCDIR/opencloud/devtools/deployments/opencloud_full/"
perl -pi -e '
s|^(OC_DOCKER_IMAGE)=.*$|$1=opencloudeu/opencloud|;
s|^(OC_DOCKER_TAG)=.*$|$1=dev|;
@@ -154,7 +159,7 @@ make -C ./opencloud/ clean build dev-docker
And then either run everything from the Docker Compose `opencloud_full` setup:
```bash
-cd "$OCDIR/opencloud/devtools/deployments/examples/opencloud_full/"
+cd "$OCDIR/opencloud/devtools/deployments/opencloud_full/"
docker compose up -d
```
@@ -243,6 +248,9 @@ go run . --empty=true --username=alan --password=demo \
For more details on the usage of that little helper tool, consult its [`README.md`](https://github.com/opencloud-eu/imap-filler/blob/main/README.md), although it is quite self-explanatory.
+> [!NOTE]
+> This only needs to be done once, since the emails are stored in a volume used by the Stalwart container.
+
# Building
If you run the `opencloud` service as a container, use the following script to update the container image and restart it:
@@ -251,6 +259,15 @@ If you run the `opencloud` service as a container, use the following script to u
oc-full-update
```
+If you prefer to do so without that script:
+
+```bash
+cd "$OCDIR/opencloud/"
+make -C opencloud/ clean build dev-docker
+cd devtools/deployments/opencloud_full/
+docker compose up -d opencloud
+```
+
If you run it from your IDE, there is obviously no need to do that.
# API Docs
@@ -280,7 +297,7 @@ Note that `redocly-cli` does not need to be installed, it will be pulled locally
This section assumes that you are using the [helper scripts in opencloud-tools](https://github.com/pbleser-oc/opencloud-tools) as instructed above.
-If you are running OpenCloud from within VSCode, then make sure to set the following environment variable first, in the shell from which you will use the scripts, as the OpenCloud process is listening to that address as opposed to and going through Traefik as is the case when running it from the Docker Compose `opencloud_full` setup:
+If you are running OpenCloud from within VSCode, then make sure to set the following environment variable `baseurl` first, in the shell from which you will use the scripts, as the OpenCloud process is listening to that address as opposed to and going through Traefik as is the case when running it from the Docker Compose `opencloud_full` setup:
```bash
export baseurl=https://localhost:9200
@@ -291,7 +308,7 @@ The scripts default to using the user `alan` (with the password `demo`), which c
* `password`
Your main swiss army knife tool will be `oc-gw` (mnemonic for "OpenCloud Groupware"), which
-* always retrieves an access token from Keycloak, using the credentials defined in `username` and `password` (defaulting to `adam`/`demo`), using the "Direct Access Grant" OIDC or "Resource Owner Password Credentials Grant" OAuth2 flow
+* always retrieves an access token from Keycloak, using the credentials defined in the environment variables `username` and `password` (defaulting to `adam`/`demo`), using the "Direct Access Grant" OIDC or "Resource Owner Password Credentials Grant" OAuth2 flow
* and then use that JWT for Bearer authentication against the OpenCloud Groupware REST API
It will also save you some typing as whenever you use `//` for the URL, it will replace that by the Groupware REST API base URL, e.g.
@@ -312,6 +329,25 @@ The first thing you might want to test is to query the index, which will ensure
oc-gw //
```
+Obviously, you may use whichever HTTP client you are most comfortable with.
+
+Here is how to do it without the `oc-gw` script, using [`curl`](https://curl.se/):
+
+First, make sure to retrieve a JWT for authentication from Keycloak:
+
+```bash
+token=$(curl --silent --insecure --fail -X POST "https://keycloak.opencloud.test/realms/openCloud/protocol/openid-connect/token" -d username="alan" -d password="demo" -d grant_type=password -d client_id="groupware" -d scope=openid | jq -r '.access_token')
+```
+
+Then use that token to authenticate the Groupware API request:
+
+```bash
+curl --insecure -s -H "Authorization: Bearer ${token}" "https://cloud.opencloud.test/groupware/"
+```
+
+> [!TIP]
+> Until everything is documented, the complete list of URI routes can be found in `$OCDIR/opencloud/services/groupware/pkg/groupware/groupware_route.go`
+
# Services
## Stalwart
@@ -324,7 +360,7 @@ To access the Stalwart admin UI, open and use
The usual admin username `admin` had to be changed into `mailadmin` because there is already an `admin` user that ships with the default users in OpenCloud, and Stalwart always checks the LDAP directory before its internal usernames.
-Those credentials are configured in `devtools/deployments/examples/opencloud_full/config/stalwart/config.toml`:
+Those credentials are configured in `devtools/deployments/opencloud_full/config/stalwart/config.toml`:
```ruby
authentication.fallback-admin.secret = "$6$4qPYDVhaUHkKcY7s$bB6qhcukb9oFNYRIvaDZgbwxrMa2RvF5dumCjkBFdX19lSNqrgKltf3aPrFMuQQKkZpK2YNuQ83hB1B3NiWzj."
authentication.fallback-admin.user = "mailadmin"
@@ -335,7 +371,7 @@ authentication.fallback-admin.user = "mailadmin"
To start with a Stalwart container from scratch, removing all the data (including emails):
```bash
-cd "$OCDIR/opencloud/devtools/deployments/examples/opencloud_full"
+cd "$OCDIR/opencloud/devtools/deployments/opencloud_full"
docker compose stop stalwart
docker compose rm stalwart
docker volume rm opencloud_full_stalwart-data