ADR: werkbak live refresh — client-side polling, not push (refs #162) #163

Open
opened 2026-09-04 08:43:47 +00:00 by not · 0 comments
Contributor

Decision to be made: how the behandel werkbak becomes live — the mechanism behind S-26/#162 ("when I submit a new registration, the werkbak updates with it").

Context / forces:

  • The werkbak is a read of the open Flowable Beoordelen tasks: portal → BFF GET /behandel/werkbak → domain Werkbak query → Flowable + registration store. Nothing today notifies anyone when a task appears.
  • A new row appears asynchronously after the citizen supplies documents (DMN routing → Beoordelen), so the trigger lives in Flowable, not in a request the portal made.
  • There is no message bus between the domain and the BFF, and the BFF holds no state. A real push to the browser therefore needs a new event path (domain → BFF) and a streaming transport (SSE/WebSocket) and connection state in the BFF.
  • This is the first live-updating view in the repo, so whatever we pick becomes the precedent.

Options considered:

  1. Client-side polling — the werkbak page re-reads the existing BFF endpoint on an interval and swaps the rows in. No new endpoint, no new dependency, no server-side state, no coupling change.
  2. SSE from the BFF (text/event-stream) — a new streaming endpoint. Since nothing notifies the BFF either, the BFF would itself poll the domain and forward diffs: the same freshness, with connection lifecycle, proxy buffering (nginx), and auth-on-long-lived-connection all added. Strictly more machinery for the same latency.
  3. WebSocket / SignalR — a new dependency (§13) and a stateful, sticky-session-bound BFF; a genuine push path would also need the domain to publish task events. Real value only for high-frequency, bidirectional or fan-out-heavy traffic; the werkbak is neither.

Proposed option + why: option 1, client-side polling. It satisfies the acceptance ("a registration can be seen in the werkbak once it is ready for review") with a handful of lines in one component, no new dependency, and no change to any service boundary. Options 2 and 3 buy nothing over it until something actually notifies the BFF — and when that day comes, the change is confined to the same component's data source.

Consequences: a bounded staleness window (one poll interval) instead of instant push; one extra GET /behandel/werkbak per open werkbak tab per interval, each costing a Flowable task query plus one store read per open task; no long-lived connections to operate. Upgrade path recorded in the ADR: publish task events from the domain, then swap the component's interval for a stream — the endpoint contract stays.

Coupling rules touched (CLAUDE.md §8): none. §8.3 (portals talk only to the BFF) and §8.2 (only the Workflow Client talks to Flowable) are unchanged — the poll reuses the existing portal → BFF → domain read path.

On acceptance, the ADR lands as docs/architecture/adr-0032-werkbak-live-refresh.md in the PR implementing #162.

**Decision to be made:** how the behandel werkbak becomes *live* — the mechanism behind S-26/#162 ("when I submit a new registration, the werkbak updates with it"). **Context / forces:** - The werkbak is a read of the open Flowable `Beoordelen` tasks: portal → BFF `GET /behandel/werkbak` → domain `Werkbak` query → Flowable + registration store. Nothing today notifies anyone when a task appears. - A new row appears asynchronously *after* the citizen supplies documents (DMN routing → `Beoordelen`), so the trigger lives in Flowable, not in a request the portal made. - There is no message bus between the domain and the BFF, and the BFF holds no state. A real *push* to the browser therefore needs a new event path (domain → BFF) **and** a streaming transport (SSE/WebSocket) **and** connection state in the BFF. - This is the first live-updating view in the repo, so whatever we pick becomes the precedent. **Options considered:** 1. **Client-side polling** — the werkbak page re-reads the existing BFF endpoint on an interval and swaps the rows in. No new endpoint, no new dependency, no server-side state, no coupling change. 2. **SSE from the BFF** (`text/event-stream`) — a new streaming endpoint. Since nothing notifies the BFF either, the BFF would itself poll the domain and forward diffs: the same freshness, with connection lifecycle, proxy buffering (nginx), and auth-on-long-lived-connection all added. Strictly more machinery for the same latency. 3. **WebSocket / SignalR** — a new dependency (§13) and a stateful, sticky-session-bound BFF; a genuine push path would also need the domain to publish task events. Real value only for high-frequency, bidirectional or fan-out-heavy traffic; the werkbak is neither. **Proposed option + why:** **option 1, client-side polling.** It satisfies the acceptance ("a registration can be seen in the werkbak once it is ready for review") with a handful of lines in one component, no new dependency, and no change to any service boundary. Options 2 and 3 buy nothing over it until something actually notifies the BFF — and when that day comes, the change is confined to the same component's data source. **Consequences:** a bounded staleness window (one poll interval) instead of instant push; one extra `GET /behandel/werkbak` per open werkbak tab per interval, each costing a Flowable task query plus one store read per open task; no long-lived connections to operate. Upgrade path recorded in the ADR: publish task events from the domain, then swap the component's interval for a stream — the endpoint contract stays. **Coupling rules touched (CLAUDE.md §8):** none. §8.3 (portals talk only to the BFF) and §8.2 (only the Workflow Client talks to Flowable) are unchanged — the poll reuses the existing portal → BFF → domain read path. > On acceptance, the ADR lands as `docs/architecture/adr-0032-werkbak-live-refresh.md` in the PR implementing #162.
not added the type:adr-proposalarea:portal-behandel labels 2026-09-04 08:44:00 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eho/register-referentie#163