Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
aca4c72
openspec: add live-updates change (notify_push backend)
rubenvdlinde May 9, 2026
7e1acc2
feat(push): add PushEvents constants for notify_push channel names
rubenvdlinde May 9, 2026
6f50f8f
feat(rbac): add PermissionHandler::getReadableByUsers() for push fan-out
rubenvdlinde May 9, 2026
22ae2fb
feat(push): implement NotifyPushListener for real-time object updates
rubenvdlinde May 9, 2026
382f0e7
feat(push): register NotifyPushListener for object lifecycle events
rubenvdlinde May 9, 2026
ba032e9
feat(push): wrap bulk-import paths in NotifyPushListener batch mode
rubenvdlinde May 9, 2026
d4a9aa8
test(push): add unit and integration tests for notify_push implementa…
rubenvdlinde May 9, 2026
cdd1793
feat(push): add admin status badge and Deck integration documentation
rubenvdlinde May 9, 2026
cee5b03
fix(quality): repair pre-existing phpcs violations and test regressions
rubenvdlinde May 9, 2026
54c71b3
docs(push): document OpenRegister's own notify_push events
rubenvdlinde May 9, 2026
6f9c0ff
feat(docker): add notify_push push server to dev compose
rubenvdlinde May 9, 2026
218a323
feat(docker): add redis service required by notify_push
rubenvdlinde May 9, 2026
b5f9110
fix(push): use notify_push wire format (user/message/body)
rubenvdlinde May 9, 2026
d34f16e
docs(push): correct OR push events wire format example
rubenvdlinde May 9, 2026
8d471a3
docs(push): add test-merge script + subscription cost guidelines
rubenvdlinde May 9, 2026
c7fa927
docs: drop revert framing from test-merge script
rubenvdlinde May 9, 2026
a22c81a
fix(push): bypass RBAC + multitenancy on listener-side schema/registe…
rubenvdlinde May 10, 2026
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
52 changes: 52 additions & 0 deletions docker-compose.yml
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[BLOCKER] Redis port 6379 bound to 0.0.0.0 with no authentication

The new redis service exposes port 6379:6379 on all host interfaces with no requirepass, no --bind 127.0.0.1. Any process reachable on the host network can read and write the Redis instance, including Nextcloud session data and the notify_push channel state. At minimum add command: redis-server --requirepass ChangeMe and align the REDIS_URL in the notify_push service.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[CONCERN] notify_push port 7867 exposed on all interfaces — unauthenticated WebSocket endpoint

The notify_push service binds port 7867:7867 on all host interfaces. Consider binding to 127.0.0.1:7867:7867 or restricting access via the Docker network.

Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,58 @@ services:
- EXAPP_OPENTALK_URL=http://openregister-exapp-opentalk:23000
- EXAPP_VALTIMO_URL=http://openregister-exapp-valtimo:23000

# Redis - shared cache backend.
# Required by notify_push (cross-process state for connected clients) AND by Nextcloud
# itself once memcache.distributed is set to \OC\Memcache\Redis (see post-up setup
# commands below). Without Redis, notify_push crashloops with "No redis server is
# configured" because it reads NC's config.php for the cache backend.
redis:
image: redis:7-alpine
container_name: redis
restart: always
ports:
- 6379:6379

# notify_push - WebSocket push server for realtime updates
# Required by OpenRegister's add-live-updates change for REST clients (frontends consume
# via @conduction/nextcloud-vue's useLiveUpdates plugin). Soft-fails when absent — OR
# works fine without this service, just without push delivery.
#
# Setup after first start (one time):
# docker exec -u www-data nextcloud php occ config:system:set redis host --value redis
# docker exec -u www-data nextcloud php occ config:system:set redis port --value 6379 --type integer
# docker exec -u www-data nextcloud php occ config:system:set memcache.distributed --value '\OC\Memcache\Redis'
# docker exec -u www-data nextcloud php occ config:system:set trusted_proxies 0 --value 172.16.0.0/12
# docker exec -u www-data nextcloud php occ notify_push:setup http://notify_push:7867
# docker exec -u www-data nextcloud php occ notify_push:self-test
#
# Image: icewind1991/notify_push (official upstream maintained by the notify_push author).
notify_push:
image: icewind1991/notify_push:latest
container_name: notify_push
restart: always
depends_on:
- nextcloud
- db
- redis
ports:
- 7867:7867
volumes:
# Mount the same NC volume the nextcloud container uses, read-only — notify_push
# reads NC's config.php and apps/notify_push/css/* from here.
- nextcloud:/nextcloud:ro
environment:
# Tell notify_push where Nextcloud lives (server-side URL, not the public one)
- NEXTCLOUD_URL=http://nextcloud
# PostgreSQL connection (matches the db service env vars above)
- DATABASE_URL=postgres://nextcloud:!ChangeMe!@db/nextcloud
# Redis URL (matches the redis service above)
- REDIS_URL=redis://redis:6379
# Logging — set to `info` for production, `trace` while debugging
- LOG=info
# Bind on all interfaces inside the container
- PORT=7867

# Nextcloud Application Server (MariaDB - For Testing)
# Start with: docker-compose --profile mariadb up
# Note: Do NOT use docker-compose up when using this profile
Expand Down
112 changes: 112 additions & 0 deletions docs/Integrations/Deck.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
title: Deck Integration
sidebar_position: 2
description: How OpenRegister integrates with the Nextcloud Deck app, including push events and card–object linking
keywords:
- OpenRegister
- Deck
- Kanban
- notify_push
- real-time
---

# Deck Integration

OpenRegister integrates with the Nextcloud Deck app to allow Kanban-style task boards to be linked directly to register objects. Deck cards represent tasks or action items; by linking them to objects you get traceable work attached to your data.

## Overview

- Deck cards can be linked to any OpenRegister object via a link table managed by `DeckCardService`.
- When a Deck board or card changes, Deck fires `notify_custom` push events via `notify_push`. Frontend consumers can listen for these events to refresh linked-object views in real time.
- OpenRegister's own push events (`or-object-*` and `or-collection-*`) complement Deck events, providing object-level invalidation alongside card-level updates.

## Backend integration

| Class | Responsibility |
|---|---|
| `OCA\OpenRegister\Service\DeckCardService` | Creates, retrieves, and deletes Deck cards linked to OR objects; wraps the Deck REST API. |
| `OCA\OpenRegister\Controller\DeckController` | REST controller exposing card link endpoints under `/api/objects/{register}/{schema}/{uuid}/deck`. |

The integration uses the Deck REST API (`/api/v1/boards`, `/api/v1/boards/{id}/stacks`, `/api/v1/boards/{id}/stacks/{stackId}/cards`) rather than the Deck PHP service layer, so it does not require Deck to be installed on the same Nextcloud instance — it can target a remote Deck instance.

## Linking cards to objects

A Deck card is linked to an OpenRegister object through the `deck` property on the `ObjectEntity`. The property holds an array of card-link descriptors:

```json
{
"@self": { "id": "550e8400-e29b-41d4-a716-446655440000" },
"deck": [
{
"boardId": 5,
"stackId": 12,
"cardId": 99,
"title": "Review permit application",
"url": "https://nextcloud.example.com/apps/deck#/board/5"
}
]
}
```

`DeckCardService` is responsible for hydrating this array and for creating new cards via the API.

The link is stored on the object itself (as part of the JSONB blob). There is no separate join table — the `deck` property is the canonical record of which cards are attached to which object.

## Push events

Deck emits `notify_custom` events via the Nextcloud `notify_push` app. Both constants live in `OCA\Deck\NotifyPushEvents`:

| Event string | Fired when | Payload fields |
|---|---|---|
| `deck_board_update` | A board is updated, a member is added/removed, or ACL changes | `id` (board ID) |
| `deck_card_update` | A card is created, updated, moved, or deleted | `boardId`, `cardId` |

These events are fired server-side by `OCA\Deck\Listeners\LiveUpdateListener`. Connected browser clients receive them via the `notify_push` WebSocket or SSE channel.

**OpenRegister contrast:** OR emits the following event strings (see `OCA\OpenRegister\Push\PushEvents`):

| Event string pattern | Fired when |
|---|---|
| `or-object-{uuid}` | Any object lifecycle event (create, update, delete) |
| `or-collection-{register-slug}-{schema-slug}` | Object created or deleted (collection invalidation) |

Deck and OR events are independent streams. A frontend widget that shows an object with linked Deck cards should subscribe to both.

## Subscribing from the frontend

`@conduction/nextcloud-vue` provides composables for subscribing to `notify_push` events. Use the `useNotifyPush` composable (available from the upcoming `add-live-updates-plugin` change):

```js
import { useNotifyPush } from '@conduction/nextcloud-vue'

const { subscribe } = useNotifyPush()

// Subscribe to object-level OR events
subscribe(`or-object-${objectUuid}`, ({ data }) => {
const payload = JSON.parse(data)
// refresh object view
})

// Subscribe to Deck card updates for the board that owns the linked card
subscribe('deck_card_update', ({ data }) => {
const { boardId, cardId } = JSON.parse(data)
// refresh card list for the affected board
})
```

Cross-reference: the `add-live-updates-plugin` change in `nextcloud-vue` provides the full composable implementation including reconnection handling and per-user event routing.

## Configuration

The Deck integration requires:

1. **notify_push installed and running** — check the admin settings Push Notifications section in OpenRegister for status.
2. **Deck app installed** — the integration uses Deck's REST API, which must be reachable.
3. **Admin credentials or app password** — `DeckCardService` uses the current user's session; board access follows Deck's own RBAC.

## Related documentation

- [n8n Integration](./n8n.md) — trigger n8n workflows on OR object events
- [Custom Webhooks](./custom-webhooks.md) — push events to arbitrary HTTP endpoints
- [Deck app documentation](https://github.com/nextcloud/deck)
- [notify_push configuration](https://github.com/nextcloud/notify_push#configuration)
Loading
Loading