Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 21 additions & 37 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,72 +1,56 @@
# Valtimo ExApp for Nextcloud
# Wraps Valtimo BPM/case management with AppAPI integration
#
# Valtimo is a less-code platform for Business Process Automation built on Camunda.
# It requires:
# - PostgreSQL or MySQL database
# - Keycloak for authentication
# - RabbitMQ for messaging (optional)
#
# See: https://docs.valtimo.nl/
# Build: docker build -t ghcr.io/conductionnl/valtimo-exapp:latest .

# Get Valtimo from official Ritense image
FROM ritense/valtimo-backend:12.0.0 AS valtimo-base

# Production image - use Eclipse Temurin JRE (matches upstream)
# Runtime: Eclipse Temurin JRE + Python for ExApp wrapper
FROM eclipse-temurin:17-jre-jammy

# Install runtime dependencies
# Install Python and runtime deps
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
tini \
python3 \
python3-pip \
curl \
tini \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*

# Install Python dependencies for ExApp wrapper
RUN pip3 install --no-cache-dir \
"fastapi>=0.109.0" \
"uvicorn>=0.27.0" \
"httpx>=0.26.0"
# Install ExApp Python dependencies
COPY requirements.txt /tmp/requirements.txt
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt

# Copy Valtimo JAR from upstream image
COPY --from=valtimo-base /app.jar /app/valtimo.jar

# Set up application directory
WORKDIR /app

# Copy ExApp wrapper
COPY ex_app /app/ex_app
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
COPY ex_app/ ex_app/
COPY entrypoint.sh .
RUN chmod +x entrypoint.sh

# Create app directories
RUN mkdir -p /app/config /app/logs

# Environment variables (set by AppAPI)
# Environment
ENV APP_HOST=0.0.0.0
ENV APP_PORT=9000
ENV APP_PORT=23000
ENV PYTHONUNBUFFERED=1

# Valtimo configuration
ENV VALTIMO_PORT=8080
ENV JAVA_OPTS="-Xmx512m -Xms256m"

# Spring Boot / Valtimo defaults (override via AppAPI env vars)
# Spring Boot defaults (override via docker-compose env vars)
ENV SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/valtimo
ENV SPRING_DATASOURCE_USERNAME=valtimo
ENV SPRING_DATASOURCE_PASSWORD=valtimo
ENV SPRING_DATASOURCE_USERNAME=nextcloud
ENV SPRING_DATASOURCE_PASSWORD=!ChangeMe!
ENV SERVER_PORT=8080

# Keycloak configuration (required)
# Keycloak (required)
ENV KEYCLOAK_AUTH_SERVER_URL=http://localhost:8081
ENV KEYCLOAK_REALM=valtimo

# Expose ports: 9000 for AppAPI, 8080 for Valtimo
EXPOSE 9000 8080

# Health check - just verify the wrapper is responding (any status is ok during init)
HEALTHCHECK --interval=30s --timeout=5s --start-period=180s --retries=3 \
CMD curl -s http://localhost:${APP_PORT:-9000}/heartbeat | grep -q status || exit 1
EXPOSE 23000 8080

ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"]
ENTRYPOINT ["/usr/bin/tini", "--", "./entrypoint.sh"]
391 changes: 190 additions & 201 deletions LICENSE

Large diffs are not rendered by default.

158 changes: 83 additions & 75 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,72 @@
# Valtimo ExApp for Nextcloud

Nextcloud ExApp (External Application) that integrates [Valtimo](https://www.valtimo.nl/) BPM and case management.

## About This App

This is a **Nextcloud ExApp** that packages the Valtimo BPM platform as a containerized application managed by Nextcloud's AppAPI. When you install this app, Nextcloud will automatically deploy and manage the Valtimo container.

**For Valtimo documentation, see:** https://docs.valtimo.nl/
<p align="center">
<img src="img/app.svg" alt="Valtimo logo" width="80" height="80">
</p>

<h1 align="center">Valtimo</h1>

<p align="center">
<strong>BPM workflow engine and case management for Nextcloud — powered by Camunda, ZGW-compliant, Common Ground compatible</strong>
</p>

<p align="center">
<a href="https://github.com/ConductionNL/valtimo/releases"><img src="https://img.shields.io/github/v/release/ConductionNL/valtimo" alt="Latest release"></a>
<a href="https://github.com/ConductionNL/valtimo/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-EUPL--1.2-blue" alt="License"></a>
</p>

---

> **DISCLAIMER**
>
> **Valtimo** is developed and maintained by [**Ritense**](https://www.ritense.com/). This Nextcloud app is a thin ExApp wrapper that packages Valtimo for deployment via Nextcloud's AppAPI. **Conduction B.V. does not provide support, licensing, guarantees, warranties, or services for the Valtimo platform itself.**
>
> For **support**, **licensing**, **pricing**, or **professional services**, contact Ritense directly:
>
> - Website: [https://www.ritense.com/](https://www.ritense.com/)
> - Valtimo platform: [https://www.valtimo.nl/](https://www.valtimo.nl/)
> - Documentation: [https://docs.valtimo.nl/](https://docs.valtimo.nl/)
> - Source code: [https://github.com/valtimo-platform/valtimo](https://github.com/valtimo-platform/valtimo)

## What is Valtimo?

Valtimo is an open-source low-code platform for Business Process Automation, built on Camunda. It is designed for Dutch municipalities and government organizations as part of the [Common Ground](https://commonground.nl/) ecosystem.
[Valtimo](https://www.valtimo.nl/) is an open-source low-code platform for Business Process Automation, built on top of the [Camunda](https://camunda.com/) BPMN engine. Developed by [Ritense](https://www.ritense.com/), it is designed for Dutch municipalities and government organizations as part of the [Common Ground](https://commonground.nl/) ecosystem.

Key features:
- BPMN workflow engine (Camunda-based)
- Case management with ZGW API compliance
- Form builder (Form.io-based dynamic forms)
- Document generation
- Integration with Common Ground components
Key capabilities of the Valtimo platform:

## What This App Does
- **BPMN Workflow Engine** -- Visual process modeling and execution powered by Camunda
- **Case Management** -- Structured case handling with ZGW API compliance
- **Form Builder** -- Dynamic forms based on Form.io for user tasks and data capture
- **Document Generation** -- Automated document creation from templates and case data
- **Common Ground Integration** -- Native support for ZGW APIs, Haal Centraal, and other Dutch government standards

- Packages Valtimo as a Nextcloud ExApp
- Nextcloud automatically manages the container lifecycle
- Provides BPM and case management directly within Nextcloud
- Integrates with Nextcloud's AppAPI for seamless deployment
## What This App Does

## Requirements
This is a **Nextcloud ExApp** (External Application) that wraps the Valtimo platform as a containerized application managed by Nextcloud's AppAPI:

- Nextcloud 30 or higher
- AppAPI app installed and configured with a deploy daemon
- Docker environment for ExApp containers
- Packages Valtimo as a Docker container managed by Nextcloud
- Nextcloud automatically handles the container lifecycle (start, stop, health monitoring)
- Provides BPM and case management capabilities directly within the Nextcloud environment
- Implements AppAPI lifecycle endpoints for seamless integration

### External Dependencies
This wrapper does **not** modify or extend Valtimo itself. It provides the integration layer between Nextcloud's AppAPI and the upstream Valtimo application.

Valtimo requires additional services for full functionality:
## Requirements

| Service | Purpose | Required |
|---------|---------|----------|
| PostgreSQL | Database | Yes |
| Keycloak | Authentication (OIDC) | Yes |
| RabbitMQ | Message broker | Optional |
| Requirement | Details |
|-------------|---------|
| Nextcloud | 30 or higher |
| AppAPI | Installed and configured with a deploy daemon |
| Docker | Environment for ExApp containers |
| PostgreSQL | Database for Valtimo (required) |
| Keycloak | OIDC authentication provider (required) |
| RabbitMQ | Message broker (optional) |

## Installation

### Via Nextcloud App Store

1. Ensure AppAPI is installed and configured
2. Search for "Valtimo" in the Nextcloud app store
3. Click Install - Nextcloud will pull and start the container
1. Ensure the **AppAPI** app is installed and configured with a deploy daemon
2. Search for **"Valtimo"** in the Nextcloud External Apps section
3. Click **Install** -- Nextcloud will pull and start the container

### Manual Registration

Expand All @@ -65,68 +83,58 @@ docker exec -u www-data nextcloud php occ app_api:app:enable valtimo

## Configuration

Configure via Nextcloud Admin Settings or environment variables:
Configure via Nextcloud Admin Settings or environment variables on the ExApp container:

| Variable | Description |
|----------|-------------|
| `SPRING_DATASOURCE_URL` | JDBC PostgreSQL connection string |
| `SPRING_DATASOURCE_URL` | JDBC PostgreSQL connection string (e.g., `jdbc:postgresql://host:5432/valtimo`) |
| `SPRING_DATASOURCE_USERNAME` | Database username |
| `SPRING_DATASOURCE_PASSWORD` | Database password |
| `KEYCLOAK_AUTH_SERVER_URL` | Keycloak authentication server URL |
| `KEYCLOAK_REALM` | Keycloak realm name |

## Development

### Building the Docker Image
| `KEYCLOAK_URL` | Keycloak server URL (e.g., `http://keycloak:8080`) |
| `KEYCLOAK_REALM` | Keycloak realm name (default: `commonground`) |
| `KEYCLOAK_CLIENT_ID` | OIDC client ID for this app (default: `valtimo`) |
| `KEYCLOAK_CLIENT_SECRET` | OIDC client secret for this app |

```bash
# Build locally
make build
## Architecture

# Push to registry
make push
This ExApp uses a FastAPI wrapper that bridges Nextcloud's AppAPI with the Valtimo Spring Boot application:

# Test locally
make test
```

### Project Structure
1. **Lifecycle management** -- Implements AppAPI endpoints (`/heartbeat`, `/init`, `/enabled`) for container orchestration
2. **Application startup** -- Starts and manages the Valtimo Spring Boot process inside the container
3. **Request proxying** -- Routes incoming requests from Nextcloud to the Valtimo backend
4. **Health reporting** -- Monitors the Valtimo process and reports status back to Nextcloud

```
valtimo/
├── appinfo/
│ └── info.xml # ExApp manifest
│ └── info.xml # ExApp manifest (routes, env vars, metadata)
├── ex_app/
│ └── lib/
│ └── main.py # FastAPI wrapper for AppAPI
│ └── main.py # FastAPI wrapper for AppAPI integration
├── Dockerfile # Container definition
├── entrypoint.sh # Container startup
├── entrypoint.sh # Container startup script
├── requirements.txt # Python dependencies
└── Makefile # Build automation
```

## Architecture
## Links

This ExApp uses a FastAPI wrapper that:

1. Implements AppAPI lifecycle endpoints (`/heartbeat`, `/init`, `/enabled`)
2. Starts and manages the Valtimo Spring Boot application
3. Proxies requests to the Valtimo backend
4. Reports health status back to Nextcloud

## Related Projects

| Project | Description | Links |
|---------|-------------|-------|
| **Valtimo** | BPM and case management platform | [Website](https://www.valtimo.nl/) / [Docs](https://docs.valtimo.nl/) / [GitHub](https://github.com/valtimo-platform) |
| **Nextcloud AppAPI** | External app framework | [GitHub](https://github.com/nextcloud/app_api) / [Docs](https://docs.nextcloud.com/server/latest/developer_manual/exapp_development/) |
| **OpenZaak** | ZGW API backend | [GitHub](https://github.com/open-zaak/open-zaak) |
| **OpenKlant** | Customer interaction registry | [GitHub](https://github.com/maykinmedia/open-klant) |
| Resource | URL |
|----------|-----|
| Valtimo website | [https://www.valtimo.nl/](https://www.valtimo.nl/) |
| Valtimo documentation | [https://docs.valtimo.nl/](https://docs.valtimo.nl/) |
| Valtimo source code | [https://github.com/valtimo-platform/valtimo](https://github.com/valtimo-platform/valtimo) |
| Ritense (developer) | [https://www.ritense.com/](https://www.ritense.com/) |
| This wrapper (GitHub) | [https://github.com/ConductionNL/valtimo](https://github.com/ConductionNL/valtimo) |
| Nextcloud AppAPI | [https://github.com/nextcloud/app_api](https://github.com/nextcloud/app_api) |
| AppAPI docs | [https://docs.nextcloud.com/server/latest/developer_manual/exapp_development/](https://docs.nextcloud.com/server/latest/developer_manual/exapp_development/) |

## License

AGPL-3.0 - See [LICENSE](LICENSE) for details.
EUPL-1.2 -- See [LICENSE](LICENSE) for details.

## Authors

## Author
**Wrapper app:** [Conduction B.V.](https://conduction.nl) -- info@conduction.nl

[Conduction B.V.](https://conduction.nl) - info@conduction.nl
**Valtimo platform:** [Ritense](https://www.ritense.com/) -- see the [Valtimo GitHub organization](https://github.com/valtimo-platform) for contributors
40 changes: 37 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "conductionnl/valtimo",
"description": "Valtimo BPM and case management integration for Nextcloud",
"license": "AGPL-3.0-or-later",
"license": "EUPL-1.2",
"authors": [
{
"name": "Conduction b.v.",
Expand All @@ -20,16 +20,50 @@
"cs:fix": "./vendor/bin/phpcbf --standard=phpcs.xml",
"phpcs": "./vendor/bin/phpcs --standard=phpcs.xml",
"phpcs:fix": "./vendor/bin/phpcbf --standard=phpcs.xml",
"psalm": "psalm --threads=1 --no-cache || echo 'Psalm not installed, skipping...'",
"phpmd": "phpmd lib text phpmd.xml || echo 'PHPMD not installed, skipping...'",
"phpmetrics": "./vendor/bin/phpmetrics --report-html=phpmetrics lib/",
"phpmetrics:violations": "./vendor/bin/phpmetrics --violations-xml=phpmetrics/violations.xml lib/",
"psalm": "./vendor/bin/psalm --threads=1 --no-cache || echo 'Psalm not installed, skipping...'",
"phpstan": "./vendor/bin/phpstan analyse --memory-limit=1G || echo 'PHPStan not installed, skipping...'",
"test:unit": "./vendor/bin/phpunit --colors=always || echo 'Tests require Nextcloud environment, skipping...'",
"test:all": "./vendor/bin/phpunit --colors=always || echo 'Tests require Nextcloud environment, skipping...'"
"test:all": "./vendor/bin/phpunit --colors=always || echo 'Tests require Nextcloud environment, skipping...'",
"check": "E=0; for CMD in lint phpcs psalm test:unit; do echo; echo \"=== $CMD ===\"; composer $CMD || E=1; done; echo; if [ $E -eq 0 ]; then echo \"ALL CHECKS PASSED\"; else echo \"SOME CHECKS FAILED (see above)\"; fi; exit $E",
"check:full": "E=0; for CMD in lint phpcs psalm phpstan test:all; do echo; echo \"=== $CMD ===\"; composer $CMD || E=1; done; echo; if [ $E -eq 0 ]; then echo \"ALL CHECKS PASSED\"; else echo \"SOME CHECKS FAILED (see above)\"; fi; exit $E",
"check:strict": "E=0; for CMD in lint phpcs phpmd psalm phpstan test:all; do echo; echo \"=== $CMD ===\"; composer $CMD || E=1; done; echo; if [ $E -eq 0 ]; then echo \"ALL CHECKS PASSED\"; else echo \"SOME CHECKS FAILED (see above)\"; fi; exit $E",
"fix": [
"@cs:fix"
],
"test:coverage": "./vendor/bin/phpunit --coverage-html=coverage/html --coverage-clover=coverage/clover.xml --colors=always",
"coverage:check": "php -r \"\\$xml = simplexml_load_file('coverage/clover.xml'); \\$metrics = \\$xml->project->metrics; \\$statements = (int)\\$metrics['statements']; \\$covered = (int)\\$metrics['coveredstatements']; \\$percentage = \\$statements > 0 ? round((\\$covered / \\$statements) * 100, 2) : 0; echo 'Coverage: ' . \\$percentage . '%' . PHP_EOL; exit(\\$percentage < 75 ? 1 : 0);\"",
"quality:phpcs-score": "./vendor/bin/phpcs --standard=phpcs.xml --report=json lib/ | php -r \"\\$json = json_decode(file_get_contents('php://stdin'), true); \\$errors = \\$json['totals']['errors'] ?? 0; \\$warnings = \\$json['totals']['warnings'] ?? 0; \\$score = 1000 - \\$errors - (\\$warnings / 2); echo 'PHPCS Score: ' . \\$score . ' (Errors: ' . \\$errors . ', Warnings: ' . \\$warnings . ')' . PHP_EOL;\"",
"quality:phpmd-score": "phpmd lib/ json phpmd.xml | php -r \"\\$input = file_get_contents('php://stdin'); \\$json = json_decode(\\$input, true); \\$violations = count(\\$json['files'] ?? []); \\$score = 1000 - (\\$violations * 10); echo 'PHPMD Score: ' . \\$score . ' (Violations: ' . \\$violations . ')' . PHP_EOL;\" || echo 'PHPMD not available'",
"quality:psalm-score": "./vendor/bin/psalm --output-format=json --no-cache | php -r \"\\$input = file_get_contents('php://stdin'); \\$json = json_decode(\\$input, true); \\$errors = count(\\$json ?? []); \\$score = 1000 - (\\$errors * 5); echo 'Psalm Score: ' . \\$score . ' (Errors: ' . \\$errors . ')' . PHP_EOL;\" || echo 'Psalm not available'",
"quality:phpstan-score": "./vendor/bin/phpstan analyse --memory-limit=1G --error-format=json --no-progress | php -r \"\\$input = file_get_contents('php://stdin'); \\$json = json_decode(\\$input, true); \\$errors = \\$json['totals']['file_errors'] ?? 0; \\$score = 1000 - (\\$errors * 5); echo 'PHPStan Score: ' . \\$score . ' (Errors: ' . \\$errors . ')' . PHP_EOL;\" || echo 'PHPStan not available'",
"quality:score": [
"@quality:phpcs-score",
"@quality:phpmd-score",
"@quality:psalm-score",
"@quality:phpstan-score"
],
"phpqa": "./vendor/bin/phpqa --report --analyzedDirs lib --buildDir phpqa",
"phpqa:full": "./vendor/bin/phpqa --report --analyzedDirs lib --buildDir phpqa --tools phpcs:0,phpmd:0,phploc:0,phpmetrics,phpcpd:0,parallel-lint:0",
"phpqa:ci": "./vendor/bin/phpqa --report --analyzedDirs lib --buildDir phpqa --tools phpcs,phpmd,phploc,phpmetrics,phpcpd,parallel-lint",
"qa:check": [
"@phpqa"
],
"qa:full": [
"@phpqa:full"
]
},
"require": {
"php": "^8.1"
},
"require-dev": {
"nextcloud/coding-standard": "^1.4",
"nextcloud/ocp": "^31.0",
"phpmd/phpmd": "^2.15",
"phpmetrics/phpmetrics": "^2.8",
"phpstan/phpstan": "^1.10",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.9",
"vimeo/psalm": "^5.26"
Expand Down
Loading
Loading