@5minds/processcube_app_sdk 8.4.0 → 8.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,58 +1,973 @@
1
- # ProcessCube.App.SDK
1
+ # ProcessCube App SDK
2
2
 
3
- Das SDK beinhaltet Komponenten und Funktionen für Frontend und Backend (Client/Server) zur einfachen und schnellen Entwicklung einer ProcessCube App auf Basis von [Next.js](https://nextjs.org/).
3
+ Das `@5minds/processcube_app_sdk` ist ein TypeScript-SDK zur Entwicklung von ProcessCube-Anwendungen mit [Next.js](https://nextjs.org/). Es stellt React-Komponenten, Server-Funktionen und gemeinsam genutzte Utilities für Prozessvisualisierung (BPMN), dynamische Formulare und die Integration mit der ProcessCube-Engine bereit.
4
4
 
5
- ## Installation zur Verwendung
5
+ ## Überblick
6
+
7
+ ### Features
8
+
9
+ - **Next.js 15+** App Router mit React 19 Server Components
10
+ - **Vollständig typisiert** durch TypeScript-Support
11
+ - **OAuth 2.0 Authentifizierung** via Authority-Integration (NextAuth + Client Credentials)
12
+ - **Ready-to-use React-Komponenten** für BPMN-Viewer, Prozess-Inspektion und dynamische Formulare
13
+ - **Sichere Engine-Kommunikation** über Server-Side Functions und Server Actions
14
+ - **Automatische Worker-Registrierung** für External Tasks
15
+ - **Authority Client** für Server-to-Server User-Administration
16
+
17
+ ### Architektur
18
+
19
+ Das SDK hat eine Drei-Schichten-Modulstruktur mit strikter Trennung:
20
+
21
+ ```mermaid
22
+ graph TD
23
+ subgraph SDK["@5minds/processcube_app_sdk"]
24
+ direction TB
25
+ Common["Common<br/><code>@5minds/processcube_app_sdk</code><br/><br/>Gemeinsame Typen, Komponenten<br/>und Funktionen"]
26
+
27
+ Server["Server<br/><code>@5minds/processcube_app_sdk/server</code><br/><br/>Engine-Client, Server Actions,<br/>External Tasks, Auth, Authority Client"]
28
+
29
+ Client["Client<br/><code>@5minds/processcube_app_sdk/client</code><br/><br/>React-Komponenten:<br/>BPMNViewer, DynamicUi,<br/>ProcessInstanceInspector"]
30
+ end
31
+
32
+ Server -->|importiert| Common
33
+ Client -->|importiert| Common
34
+
35
+ Engine["ProcessCube Engine"]
36
+ Authority["ProcessCube Authority"]
37
+ Browser["Browser / React"]
38
+
39
+ Server -->|HTTP| Engine
40
+ Server -->|OAuth2 / HTTP| Authority
41
+ Client --> Browser
42
+ ```
43
+
44
+ ### Export-Map
45
+
46
+ Das Paket hat drei Einstiegspunkte — jeder mit ESM- und CJS-Support:
47
+
48
+ ```mermaid
49
+ graph LR
50
+ subgraph Imports
51
+ I1["import _ from<br/>'@5minds/processcube_app_sdk'"]
52
+ I2["import _ from<br/>'@5minds/processcube_app_sdk/server'"]
53
+ I3["import _ from<br/>'@5minds/processcube_app_sdk/client'"]
54
+ I4["import<br/>'…/client/components/*.css'"]
55
+ end
56
+
57
+ I1 --> Common["common/index.mjs<br/><small>.cjs</small>"]
58
+ I2 --> Server["server/index.mjs<br/><small>.cjs</small>"]
59
+ I3 --> Client["client/index.mjs<br/><small>.cjs</small>"]
60
+ I4 --> CSS["components/*.css"]
61
+ ```
62
+
63
+ | Import-Pfad | Inhalt | Umgebung |
64
+ | ------------------------------------ | ------------------------------------------------------------------------- | --------------- |
65
+ | `@5minds/processcube_app_sdk` | Gemeinsame Typen, `RemoteUserTask`, `hasClaim`, Auth-Callbacks | Client + Server |
66
+ | `@5minds/processcube_app_sdk/server` | Engine-Funktionen, Server Actions, Auth, Authority Client, External Tasks | Nur Server |
67
+ | `@5minds/processcube_app_sdk/client` | React-Komponenten (BPMNViewer, DynamicUi, ProcessInstanceInspector, …) | Nur Client |
68
+ | `…/client/components/*.css` | Komponent-spezifische Stylesheets | CSS-Import |
69
+
70
+ ## Installation
6
71
 
7
72
  ### Voraussetzungen
8
73
 
9
- - NodeJS `>= v24`
74
+ - Node.js >= 24
75
+ - Next.js >= 15
76
+ - React >= 19
10
77
 
11
- ```shell
12
- npm i @5minds/processcube_app_sdk
78
+ ### Paket installieren
79
+
80
+ ```bash
81
+ npm install @5minds/processcube_app_sdk
13
82
  ```
14
83
 
15
- ## Benutzung
84
+ ### Next.js konfigurieren
85
+
86
+ Die einfachste Konfiguration mit dem SDK-Plugin:
87
+
88
+ ```typescript
89
+ // next.config.ts
90
+ import { withApplicationSdk } from '@5minds/processcube_app_sdk/server';
16
91
 
17
- Das NPM Paket hat _drei_ Exports.
92
+ export default withApplicationSdk({
93
+ applicationSdk: {
94
+ useExternalTasks: true,
95
+ },
96
+ });
97
+ ```
18
98
 
19
- ### Default/Common
99
+ Ohne External Tasks reicht:
20
100
 
21
- Hier werden Komponenten und Funktionen exportiert, die im Client und Server genutzt werden können.
101
+ ```typescript
102
+ // next.config.ts
103
+ import type { NextConfig } from 'next';
22
104
 
23
- Zum Beispiel die React Komponente RemoteUserTask:
105
+ const nextConfig: NextConfig = {
106
+ serverExternalPackages: ['esbuild'],
107
+ };
24
108
 
25
- ```javascript
26
- import { RemoteUserTask } from '@5minds/processcube_app_sdk';
109
+ export default nextConfig;
110
+ ```
111
+
112
+ ### CSS einbinden
113
+
114
+ Der einfachste Weg: Importiere alle SDK-Styles auf einmal im Root-Layout:
115
+
116
+ ```typescript
117
+ // app/layout.tsx
118
+ import '@5minds/processcube_app_sdk/client/styles';
119
+ ```
120
+
121
+ Alternativ können einzelne Komponenten-Stylesheets importiert werden:
122
+
123
+ ```typescript
124
+ import '@5minds/processcube_app_sdk/client/components/ProcessInstanceInspector/ProcessInstanceInspector.css';
125
+ import '@5minds/processcube_app_sdk/client/components/BPMNViewer.css';
126
+ ```
127
+
128
+ > **Hinweis:** Die `DynamicUi`-Komponente importiert ihr CSS automatisch. Ein separater CSS-Import ist dafür nicht nötig.
129
+
130
+ ### Umgebungsvariablen
131
+
132
+ Erstelle eine `.env.local` im Projekt-Root:
133
+
134
+ ```bash
135
+ # Pflicht
136
+ PROCESSCUBE_ENGINE_URL=http://localhost:10560
137
+
138
+ # Für Authentifizierung (optional)
139
+ PROCESSCUBE_AUTHORITY_URL=http://localhost:11560
140
+ NEXTAUTH_CLIENT_ID=my_client_id
141
+ NEXTAUTH_SECRET=my_secret
142
+ ```
143
+
144
+ Die vollständige Liste aller Umgebungsvariablen findest du im Abschnitt [Konfiguration](#konfiguration).
145
+
146
+ ## Authentifizierung
147
+
148
+ Das SDK bietet zwei Authentifizierungs-Strategien für unterschiedliche Anwendungsfälle:
149
+
150
+ ```mermaid
151
+ flowchart TD
152
+ Start["Authentifizierung benötigt"] --> Q1{"Wer handelt?"}
153
+
154
+ Q1 -->|"Eingeloggter Benutzer<br/>(Browser-Session)"| UserPath["User-Identity<br/><code>getIdentity()</code>"]
155
+ Q1 -->|"Server/Service<br/>(kein Benutzerkontext)"| ServerPath["Server-Identity<br/><code>getServerIdentity()</code>"]
156
+
157
+ UserPath --> U1["NextAuth JWT aus Cookie"]
158
+ U1 --> U2["Automatischer Token-Refresh"]
159
+ U2 --> U3["Identity: { token, userId }"]
160
+
161
+ ServerPath --> S1["Client Credentials Grant"]
162
+ S1 --> S2["Token-Cache mit Auto-Refresh"]
163
+ S2 --> S3["Identity: { token, userId }"]
164
+
165
+ U3 --> UseCase1["Server Components<br/>Server Actions<br/>API Routes"]
166
+ S3 --> UseCase2["External Tasks<br/>Cron-Jobs<br/>Authority Admin API"]
167
+
168
+ style UserPath fill:#e0f0ff
169
+ style ServerPath fill:#fff0e0
170
+ ```
171
+
172
+ ### User-Identity (NextAuth-basiert)
173
+
174
+ Für Server Components und Server Actions, die im Kontext eines eingeloggten Benutzers laufen:
175
+
176
+ #### getIdentity()
177
+
178
+ Gibt die Identity des aktuell eingeloggten Benutzers zurück. Nutzt das NextAuth-JWT aus dem Session-Cookie.
179
+
180
+ ```typescript
181
+ import { getIdentity } from '@5minds/processcube_app_sdk/server';
182
+
183
+ export default async function MyPage() {
184
+ const identity = await getIdentity();
185
+ // identity.token — Access Token
186
+ // identity.userId — User ID (sub Claim)
187
+ }
188
+ ```
189
+
190
+ Der Token wird automatisch erneuert, wenn er abgelaufen ist. Voraussetzung: `PROCESSCUBE_AUTHORITY_URL`, `NEXTAUTH_CLIENT_ID` und `NEXTAUTH_SECRET` sind gesetzt.
191
+
192
+ #### hasClaim()
193
+
194
+ Prüft, ob der aktuelle Benutzer einen bestimmten Claim besitzt. Funktioniert sowohl in Server Components als auch im Client.
195
+
196
+ ```typescript
197
+ import { hasClaim } from '@5minds/processcube_app_sdk';
198
+
199
+ const isAdmin = await hasClaim('admin');
200
+ ```
201
+
202
+ #### Auth-Callbacks für NextAuth
203
+
204
+ Das SDK exportiert vorkonfigurierte Callbacks für die NextAuth-Konfiguration:
205
+
206
+ ```typescript
207
+ import { authConfigJwtCallback, authConfigSessionCallback } from '@5minds/processcube_app_sdk';
208
+
209
+ export const authOptions = {
210
+ callbacks: {
211
+ jwt: authConfigJwtCallback,
212
+ session: authConfigSessionCallback,
213
+ },
214
+ // ... weitere NextAuth-Konfiguration
215
+ };
216
+ ```
217
+
218
+ | Callback | Aufgabe |
219
+ | --------------------------- | ------------------------------------------------------------------------------------------------------- |
220
+ | `authConfigJwtCallback` | Überträgt Access Token, ID Token und Refresh Token in das JWT. Erneuert abgelaufene Tokens automatisch. |
221
+ | `authConfigSessionCallback` | Extrahiert Claims aus dem Access Token und stellt sie in `session.user.claims` bereit. |
222
+
223
+ ### Server-Identity (Client Credentials)
224
+
225
+ Für Server-to-Server-Kommunikation ohne Benutzerkontext — typischerweise in External Tasks, Cron-Jobs oder Authority-Admin-Operationen:
226
+
227
+ #### getServerAccessToken()
228
+
229
+ Holt einen Access Token über den OAuth2 Client Credentials Grant. Der Token wird gecacht und automatisch vor Ablauf erneuert.
230
+
231
+ ```typescript
232
+ import { getServerAccessToken } from '@5minds/processcube_app_sdk/server';
233
+
234
+ const token = await getServerAccessToken();
235
+ ```
236
+
237
+ ```mermaid
238
+ sequenceDiagram
239
+ participant App as Anwendung
240
+ participant Cache as Token-Cache
241
+ participant Auth as Authority
242
+
243
+ App->>Cache: getServerAccessToken()
244
+ alt Token im Cache und gültig
245
+ Cache-->>App: Gecachter Token
246
+ else Kein Token oder abgelaufen
247
+ Cache->>Auth: POST /token<br/>(client_credentials)
248
+ alt Erfolg
249
+ Auth-->>Cache: { access_token, expires_in }
250
+ Note over Cache: Token speichern<br/>(Ablauf × 0.85 Buffer)
251
+ Cache-->>App: Neuer Token
252
+ else Fehler (401/403 — Client gesperrt)
253
+ Auth-->>Cache: HTTP Error
254
+ Cache-->>App: Error wird geworfen
255
+ end
256
+ end
257
+ ```
258
+
259
+ **Optionen:**
260
+
261
+ ```typescript
262
+ interface ServerAccessTokenOptions {
263
+ clientId?: string; // Default: PROCESSCUBE_SERVER_CLIENT_ID
264
+ clientSecret?: string; // Default: PROCESSCUBE_SERVER_CLIENT_SECRET
265
+ scopes?: string; // Default: PROCESSCUBE_SERVER_SCOPES oder 'upe_admin engine_read engine_write'
266
+ authorityUrl?: string; // Default: PROCESSCUBE_AUTHORITY_URL
267
+ skipCache?: boolean; // Cache umgehen und frischen Token holen
268
+ }
269
+ ```
270
+
271
+ #### getServerIdentity()
272
+
273
+ Wrapper um `getServerAccessToken()`, der direkt ein `Identity`-Objekt zurückgibt:
274
+
275
+ ```typescript
276
+ import { getServerIdentity } from '@5minds/processcube_app_sdk/server';
277
+
278
+ const identity = await getServerIdentity();
279
+ // identity.token — Access Token
280
+ // identity.userId — Service-Account User ID
281
+ ```
282
+
283
+ ### Authority Client
284
+
285
+ Der `AuthorityClient` bietet authentifizierten Zugriff auf die ProcessCube Authority API — in zwei Stufen:
286
+
287
+ ```mermaid
288
+ classDiagram
289
+ class AuthorityClient {
290
+ -authorityUrl: string
291
+ -tokenOptions: ServerAccessTokenOptions
292
+ +constructor(options?: AuthorityClientOptions)
293
+ +request(method, path, body?) AuthorityResponse~T~
294
+ +updateClaim(username, claimName, claimValue) AuthorityResponse
295
+ +addScope(username, scopeName) AuthorityResponse
296
+ +addGroup(username, groupName) AuthorityResponse
297
+ +deleteUser(username, options?) AuthorityResponse
298
+ }
299
+
300
+ class AuthorityResponse~T~ {
301
+ +ok: boolean
302
+ +status: number
303
+ +data: T
304
+ }
305
+
306
+ AuthorityClient --> AuthorityResponse : gibt zurück
307
+ ```
308
+
309
+ #### Stufe 1 — Allgemein: request()
310
+
311
+ Für beliebige Authority-API-Aufrufe. Der Token wird automatisch beschafft und als Cookie gesendet:
312
+
313
+ ```typescript
314
+ import { AuthorityClient } from '@5minds/processcube_app_sdk/server';
315
+
316
+ const authority = new AuthorityClient();
317
+
318
+ // Beliebiger API-Aufruf
319
+ const response = await authority.request('GET', '/acr/username_password/admin/users');
320
+ if (response.ok) {
321
+ console.log(response.data);
322
+ }
323
+ ```
324
+
325
+ #### Stufe 2 — Convenience-Methoden
326
+
327
+ Vordefinierte Methoden für häufige User-Admin-Operationen:
328
+
329
+ ```typescript
330
+ import { AuthorityClient } from '@5minds/processcube_app_sdk/server';
331
+
332
+ const authority = new AuthorityClient();
333
+
334
+ // Claim setzen
335
+ await authority.updateClaim('user@example.com', 'email_verified', true);
336
+
337
+ // Scope hinzufügen
338
+ await authority.addScope('user@example.com', 'premium_content');
339
+
340
+ // Gruppe zuweisen
341
+ await authority.addGroup('user@example.com', 'Partner-Netzwerk');
342
+
343
+ // User soft-deleten
344
+ const result = await authority.deleteUser('user@example.com', { fullDelete: false });
345
+ ```
346
+
347
+ | Methode | HTTP | Beschreibung |
348
+ | ---------------------------------------------- | ------ | -------------------------------------- |
349
+ | `updateClaim(username, claimName, claimValue)` | PATCH | Setzt einen Claim auf dem User-Account |
350
+ | `addScope(username, scopeName)` | PATCH | Fügt einen Scope zum User hinzu |
351
+ | `addGroup(username, groupName)` | PATCH | Fügt den User einer Gruppe hinzu |
352
+ | `deleteUser(username, { fullDelete? })` | DELETE | Löscht oder soft-deleted einen User |
353
+
354
+ Alle Methoden geben ein `AuthorityResponse<T>` zurück mit `ok`, `status` und `data`.
355
+
356
+ #### Beispiel: External Task mit Authority Client
357
+
358
+ Vorher (ohne SDK-Helper):
359
+
360
+ ```typescript
361
+ export default async function (payload: any) {
362
+ const response = await fetch(`${process.env.PROCESSCUBE_AUTHORITY_URL}/token`, {
363
+ method: 'POST',
364
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
365
+ body: new URLSearchParams({
366
+ grant_type: 'client_credentials',
367
+ client_id: process.env.PROCESSCUBE_SERVER_CLIENT_ID,
368
+ client_secret: process.env.PROCESSCUBE_SERVER_CLIENT_SECRET,
369
+ scope: 'upe_admin engine_read engine_write',
370
+ }).toString(),
371
+ });
372
+ const { access_token } = await response.json();
373
+
374
+ const result = await fetch(`${process.env.PROCESSCUBE_AUTHORITY_URL}/acr/username_password/admin/user/${payload.email}/delete`, {
375
+ method: 'DELETE',
376
+ headers: { Cookie: `access_token=${access_token}`, 'Content-Type': 'application/json' },
377
+ body: JSON.stringify({ fullDelete: false }),
378
+ });
379
+ return { completed_successful: result.ok };
380
+ }
381
+ ```
382
+
383
+ Nachher (mit Authority Client):
384
+
385
+ ```typescript
386
+ import { AuthorityClient } from '@5minds/processcube_app_sdk/server';
387
+
388
+ export default async function (payload: any) {
389
+ const authority = new AuthorityClient();
390
+ const result = await authority.deleteUser(payload.email, { fullDelete: false });
391
+ return { completed_successful: result.ok };
392
+ }
393
+ ```
394
+
395
+ ## Konfiguration
396
+
397
+ ### withApplicationSdk Plugin
398
+
399
+ Das SDK-Plugin für Next.js konfiguriert die Anwendung automatisch und startet bei Bedarf External Task Worker:
400
+
401
+ ```typescript
402
+ import { withApplicationSdk } from '@5minds/processcube_app_sdk/server';
403
+
404
+ export default withApplicationSdk({
405
+ applicationSdk: {
406
+ useExternalTasks: true,
407
+ customExternalTasksDirPath: './my-tasks', // Optional
408
+ },
409
+ // Weitere Next.js-Optionen hier
410
+ });
411
+ ```
412
+
413
+ | Option | Typ | Standard | Beschreibung |
414
+ | ---------------------------- | --------- | ------------------------ | ------------------------------------- |
415
+ | `useExternalTasks` | `boolean` | `false` | External Task Worker aktivieren |
416
+ | `customExternalTasksDirPath` | `string` | `./app` oder `./src/app` | Verzeichnis für External Task Handler |
417
+
418
+ Das Plugin fügt automatisch `esbuild` zu `serverExternalPackages` hinzu und startet Worker nur im Server-Modus (nicht während `next build`).
419
+
420
+ ### Umgebungsvariablen
421
+
422
+ #### Allgemein
423
+
424
+ | Variable | Pflicht | Standard | Beschreibung |
425
+ | --------------------------- | ------- | ------------------------ | -------------------------------------------------------------------------- |
426
+ | `PROCESSCUBE_ENGINE_URL` | Nein | `http://localhost:10560` | URL der ProcessCube Engine |
427
+ | `PROCESSCUBE_AUTHORITY_URL` | Nein | — | URL der ProcessCube Authority. Aktiviert Token-basierte Authentifizierung. |
428
+
429
+ #### User-Identity (NextAuth)
430
+
431
+ | Variable | Pflicht | Standard | Beschreibung |
432
+ | -------------------- | -------------- | ----------- | -------------------------------------------- |
433
+ | `NEXTAUTH_CLIENT_ID` | Wenn Authority | — | OAuth2 Client ID für den Benutzer-Login |
434
+ | `NEXTAUTH_SECRET` | Wenn Authority | — | Secret für NextAuth JWT-Verschlüsselung |
435
+ | `NEXTAUTH_URL` | Nein | Auto-Detect | URL der NextAuth-Instanz (für Token-Refresh) |
436
+
437
+ #### Server-Identity (Client Credentials)
438
+
439
+ | Variable | Pflicht | Standard | Beschreibung |
440
+ | ---------------------------------- | -------------------- | ------------------------------------ | ------------------------------------------ |
441
+ | `PROCESSCUBE_SERVER_CLIENT_ID` | Wenn Server-Identity | — | OAuth2 Client ID für Server-to-Server Auth |
442
+ | `PROCESSCUBE_SERVER_CLIENT_SECRET` | Wenn Server-Identity | — | OAuth2 Client Secret |
443
+ | `PROCESSCUBE_SERVER_SCOPES` | Nein | `upe_admin engine_read engine_write` | Scopes für den Server-Token |
444
+
445
+ #### External Task Worker
446
+
447
+ | Variable | Pflicht | Standard | Beschreibung |
448
+ | ------------------------------------------------ | -------------- | -------- | ---------------------------------------------- |
449
+ | `PROCESSCUBE_EXTERNAL_TASK_WORKER_CLIENT_ID` | Wenn Authority | — | Client ID für External Task Worker Auth |
450
+ | `PROCESSCUBE_EXTERNAL_TASK_WORKER_CLIENT_SECRET` | Wenn Authority | — | Client Secret für External Task Worker Auth |
451
+ | `PROCESSCUBE_APP_SDK_ETW_RETRY` | Nein | `6` | Max. Reconnect-Versuche bei Verbindungsfehlern |
452
+
453
+ ## Server-Funktionen
454
+
455
+ ### Übersicht
456
+
457
+ Alle Server-Funktionen werden aus `@5minds/processcube_app_sdk/server` importiert und können in Server Components, Server Actions und API Routes verwendet werden.
458
+
459
+ | Kategorie | Funktionen |
460
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
461
+ | **Authentifizierung** | `getIdentity`, `getServerAccessToken`, `getServerIdentity` |
462
+ | **Authority** | `AuthorityClient` |
463
+ | **Process-Instanzen** | `getProcessInstanceById`, `getActiveProcessInstances`, `retryProcessInstance`, `terminateProcessInstance`, `waitForProcessEnd`, `getFlowNodeInstancesByProcessInstanceId`, `getFlowNodeInstancesTriggeredByFlowNodeInstanceIds` |
464
+ | **User Tasks** | `getUserTasks`, `getWaitingUserTasks`, `getWaitingUserTasksByProcessInstanceId`, `getWaitingUserTasksByFlowNodeId`, `getWaitingUserTaskByFlowNodeInstanceId`, `getWaitingUserTasksByCorrelationId`, `getReservedUserTasksByIdentity`, `getAssignedUserTasksByIdentity`, `waitForUserTask`, `finishUserTaskAndGetNext`, `reserveUserTask`, `cancelReservedUserTask` |
465
+ | **Server Actions** | `startProcess`, `finishUserTask`, `finishManualTask`, `finishUntypedTask`, `finishTask`, `navigateToUrl` |
466
+ | **Engine** | `getEngineClient` |
467
+ | **Plugin** | `withApplicationSdk` |
468
+ | **External Tasks** | `ExternalTaskConfig` (Type) |
469
+
470
+ ### Process-Instanzen
471
+
472
+ #### getProcessInstanceById
473
+
474
+ Gibt die Prozessinstanz mit der angegebenen ID zurück (inkl. BPMN-XML).
475
+
476
+ ```typescript
477
+ import { getProcessInstanceById } from '@5minds/processcube_app_sdk/server';
478
+
479
+ const instance = await getProcessInstanceById('process-instance-id');
27
480
  ```
28
481
 
29
- ### Server
482
+ #### getActiveProcessInstances
30
483
 
31
- Hier steht alles ausschließlich für eine serverseitige Umgebung zur Verfügung. Dazu zählen Funktionen, die mit der Engine arbeiten, oder React Komponenten, die Serverseitig gerendert werden können.
484
+ Gibt alle laufenden Prozessinstanzen zurück. Unterstützt Filterung und Paginierung.
32
485
 
33
- Beispiel:
486
+ ```typescript
487
+ import { getActiveProcessInstances } from '@5minds/processcube_app_sdk/server';
488
+
489
+ // Alle laufenden Instanzen
490
+ const result = await getActiveProcessInstances();
491
+
492
+ // Mit Filter
493
+ const filtered = await getActiveProcessInstances({
494
+ query: { processModelId: 'OrderProcess' },
495
+ options: { limit: 10, offset: 0 },
496
+ });
497
+ ```
498
+
499
+ #### retryProcessInstance
500
+
501
+ Startet eine Prozessinstanz von einem bestimmten FlowNode neu.
502
+
503
+ ```typescript
504
+ import { retryProcessInstance } from '@5minds/processcube_app_sdk/server';
505
+
506
+ // Gesamten Prozess neu starten
507
+ await retryProcessInstance('process-instance-id');
508
+
509
+ // Ab einem bestimmten FlowNode
510
+ await retryProcessInstance('process-instance-id', 'flow-node-instance-id');
511
+
512
+ // Mit neuem Start-Token
513
+ await retryProcessInstance('process-instance-id', 'flow-node-instance-id', { orderId: 'new-123' });
514
+ ```
515
+
516
+ #### terminateProcessInstance
517
+
518
+ Beendet eine Prozessinstanz sofort.
519
+
520
+ ```typescript
521
+ import { terminateProcessInstance } from '@5minds/processcube_app_sdk/server';
522
+
523
+ await terminateProcessInstance('process-instance-id');
524
+ ```
525
+
526
+ #### waitForProcessEnd
527
+
528
+ Wartet, bis eine Prozessinstanz beendet, terminiert oder fehlerhaft ist. Nutzt Engine-Notifications (kein Polling).
529
+
530
+ ```typescript
531
+ import { waitForProcessEnd } from '@5minds/processcube_app_sdk/server';
34
532
 
35
- ```javascript
36
- import { startProcess } from '@5minds/processcube_app_sdk/server';
533
+ const finishedInstance = await waitForProcessEnd({
534
+ processInstanceId: 'process-instance-id',
535
+ });
536
+ ```
537
+
538
+ #### getFlowNodeInstancesByProcessInstanceId
539
+
540
+ Gibt alle FlowNode-Instanzen einer Prozessinstanz zurück (sortiert nach Erstellungsdatum).
541
+
542
+ ```typescript
543
+ import { getFlowNodeInstancesByProcessInstanceId } from '@5minds/processcube_app_sdk/server';
544
+
545
+ const flowNodes = await getFlowNodeInstancesByProcessInstanceId('process-instance-id');
37
546
  ```
38
547
 
39
- Um die Engine URL anzupassen, die von den exportierten Funktionen genutzt wird, muss `PROCESSCUBE_ENGINE_URL` als Umgebungsvariable gesetzt werden. Andernfalls wird localhost mit dem Standardport der Engine genutzt `10560`.
548
+ #### getFlowNodeInstancesTriggeredByFlowNodeInstanceIds
549
+
550
+ Gibt FlowNode-Instanzen zurück, die von den angegebenen FlowNode-Instanzen ausgelöst wurden.
551
+
552
+ ```typescript
553
+ import { getFlowNodeInstancesTriggeredByFlowNodeInstanceIds } from '@5minds/processcube_app_sdk/server';
554
+
555
+ const triggered = await getFlowNodeInstancesTriggeredByFlowNodeInstanceIds(['fni-1', 'fni-2']);
556
+ ```
40
557
 
41
- ### Client
558
+ ### User Tasks
559
+
560
+ > **Blocking vs. Non-Blocking:** Einige Funktionen blocken, bis ein Event eintritt. Das ist wichtig für die Wahl der richtigen Funktion:
561
+ >
562
+ > | Funktion | Blockiert? | Use-Case |
563
+ > | ----------------------- | ---------- | -------------------------------------------------- |
564
+ > | `waitForUserTask()` | **Ja** | Server-seitig auf nächsten Task warten (Event-Sub) |
565
+ > | `getWaitingUserTasks()` | Nein | Polling, UI-Abfragen, Server Components |
566
+ > | `getUserTasks()` | Nein | Allgemeine Abfrage mit vollem Query-Objekt |
567
+ > | `waitForProcessEnd()` | **Ja** | Warten bis Prozess beendet (Event-Sub) |
568
+
569
+ #### getWaitingUserTasks
570
+
571
+ Gibt alle wartenden User Tasks zurück.
572
+
573
+ ```typescript
574
+ import { getWaitingUserTasks } from '@5minds/processcube_app_sdk/server';
575
+
576
+ const { userTasks, totalCount } = await getWaitingUserTasks();
577
+ ```
578
+
579
+ #### getWaitingUserTasksByProcessInstanceId
580
+
581
+ Filtert wartende User Tasks nach Prozessinstanz.
582
+
583
+ ```typescript
584
+ import { getWaitingUserTasksByProcessInstanceId } from '@5minds/processcube_app_sdk/server';
42
585
 
43
- Es können nur Komponenten und Funktionen importiert werden, die im Browser funktionieren. Zum Beispiel React Komponenten, die einen clientseitigen Router und dessen React Hooks nutzen oder Funktionen, die auf `window` oder generell globale Browser APIs zugreifen möchten.
586
+ const { userTasks } = await getWaitingUserTasksByProcessInstanceId('process-instance-id');
44
587
 
45
- ```javascript
46
- import { DynamicLink } from '@5minds/processcube_app_sdk/client';
588
+ // Auch mit Array von IDs
589
+ const { userTasks: multiple } = await getWaitingUserTasksByProcessInstanceId(['id-1', 'id-2']);
47
590
  ```
48
591
 
49
- ### External Tasks
592
+ #### getWaitingUserTaskByFlowNodeInstanceId
593
+
594
+ Gibt eine einzelne wartende User Task nach FlowNode-Instanz-ID zurück (oder `null`).
595
+
596
+ ```typescript
597
+ import { getWaitingUserTaskByFlowNodeInstanceId } from '@5minds/processcube_app_sdk/server';
598
+
599
+ const userTask = await getWaitingUserTaskByFlowNodeInstanceId('flow-node-instance-id');
600
+ ```
601
+
602
+ #### waitForUserTask
603
+
604
+ Wartet auf die nächste wartende User Task. Falls bereits eine existiert, wird sie sofort zurückgegeben.
605
+
606
+ ```typescript
607
+ import { waitForUserTask } from '@5minds/processcube_app_sdk/server';
608
+
609
+ // Auf beliebige User Task warten
610
+ const userTask = await waitForUserTask();
611
+
612
+ // Mit Filter
613
+ const filtered = await waitForUserTask({
614
+ processInstanceId: 'process-instance-id',
615
+ flowNodeId: 'UserTask_Approve',
616
+ });
617
+ ```
618
+
619
+ #### finishUserTaskAndGetNext
620
+
621
+ Schließt eine User Task ab und gibt die nächste wartende User Task zurück (falls vorhanden).
622
+
623
+ ```typescript
624
+ import { finishUserTaskAndGetNext } from '@5minds/processcube_app_sdk/server';
625
+
626
+ const nextTask = await finishUserTaskAndGetNext('flow-node-instance-id', { processInstanceId: 'process-instance-id' }, { approved: true });
627
+ ```
628
+
629
+ #### reserveUserTask / cancelReservedUserTask
630
+
631
+ Reserviert eine User Task für einen bestimmten Benutzer oder hebt die Reservierung auf.
632
+
633
+ ```typescript
634
+ import { reserveUserTask, cancelReservedUserTask, getIdentity } from '@5minds/processcube_app_sdk/server';
635
+
636
+ const identity = await getIdentity();
637
+ await reserveUserTask(identity, 'flow-node-instance-id');
638
+
639
+ // Reservierung aufheben
640
+ await cancelReservedUserTask(identity, 'flow-node-instance-id');
641
+ ```
642
+
643
+ #### Weitere User-Task-Funktionen
644
+
645
+ | Funktion | Beschreibung |
646
+ | ------------------------------------------------------------- | ------------------------------------------ |
647
+ | `getUserTasks(query, options?)` | Generische Abfrage mit vollem Query-Objekt |
648
+ | `getWaitingUserTasksByFlowNodeId(flowNodeId, options?)` | Filter nach BPMN-FlowNode-ID |
649
+ | `getWaitingUserTasksByCorrelationId(correlationId, options?)` | Filter nach Correlation-ID |
650
+ | `getReservedUserTasksByIdentity(identity?, options?)` | Vom aktuellen User reservierte Tasks |
651
+ | `getAssignedUserTasksByIdentity(identity?, options?)` | Dem aktuellen User zugewiesene Tasks |
652
+
653
+ Alle Funktionen unterstützen einen `identity`-Parameter:
654
+
655
+ | Wert | Verhalten |
656
+ | ----------------- | ------------------------------------------------------------------------------------------------------- |
657
+ | `true` (Default) | Nutzt die implizite User-Identity aus der NextAuth-Session |
658
+ | `false` | Anonymer Zugriff — kein Auth-Header. Voraussetzung: Engine muss `allowAnonymousRootAccess: true` haben. |
659
+ | `Identity`-Objekt | Explizite Identity (z.B. von `getServerIdentity()` oder `getIdentity()`) |
660
+
661
+ ### Server Actions
662
+
663
+ Server Actions sind für den Aufruf aus Client Components oder Formularen gedacht:
664
+
665
+ ```typescript
666
+ import { startProcess, finishUserTask, navigateToUrl } from '@5minds/processcube_app_sdk/server';
667
+ ```
668
+
669
+ | Action | Beschreibung |
670
+ | ------------------------------------------------------- | --------------------------------------------------------- |
671
+ | `startProcess(...)` | Startet eine Prozessinstanz (Argumente wie Engine-Client) |
672
+ | `finishUserTask(flowNodeInstanceId, result, identity?)` | Schließt eine User Task ab |
673
+ | `finishManualTask(flowNodeInstanceId, identity?)` | Schließt eine Manual Task ab |
674
+ | `finishUntypedTask(flowNodeInstanceId, identity?)` | Schließt eine generische bpmn:Task ab |
675
+ | `finishTask(flowNodeInstanceId, flowNodeType)` | Universelle Finish-Funktion (erkennt Task-Typ) |
676
+ | `navigateToUrl(url)` | Server-seitige Weiterleitung via Next.js `redirect()` |
677
+
678
+ **Beispiel: Server Action in einem Formular**
679
+
680
+ ```typescript
681
+ // app/tasks/page.tsx
682
+ import { finishUserTask, getWaitingUserTasks } from '@5minds/processcube_app_sdk/server';
683
+ import { revalidatePath } from 'next/cache';
684
+
685
+ export default async function TasksPage() {
686
+ const { userTasks } = await getWaitingUserTasks();
687
+
688
+ async function handleFinish(flowNodeInstanceId: string) {
689
+ 'use server';
690
+ await finishUserTask(flowNodeInstanceId, { approved: true });
691
+ revalidatePath('/tasks');
692
+ }
693
+
694
+ return (
695
+ <ul>
696
+ {userTasks.map((task) => (
697
+ <li key={task.flowNodeInstanceId}>
698
+ {task.flowNodeName}
699
+ <form action={handleFinish.bind(null, task.flowNodeInstanceId)}>
700
+ <button type="submit">Abschließen</button>
701
+ </form>
702
+ </li>
703
+ ))}
704
+ </ul>
705
+ );
706
+ }
707
+ ```
708
+
709
+ ### Engine Client
710
+
711
+ Für direkte Zugriffe auf die Engine-API, die nicht durch die SDK-Funktionen abgedeckt sind:
712
+
713
+ ```typescript
714
+ import { getEngineClient } from '@5minds/processcube_app_sdk/server';
715
+
716
+ const client = getEngineClient();
717
+ // Zugriff auf alle Engine-Client-APIs
718
+ const models = await client.processModels.getProcessModels();
719
+ ```
720
+
721
+ Der Client ist ein Singleton und nutzt die `PROCESSCUBE_ENGINE_URL`.
722
+
723
+ ## Client-Komponenten
724
+
725
+ Alle Client-Komponenten werden aus `@5minds/processcube_app_sdk/client` importiert und müssen in Dateien mit `'use client'` verwendet werden.
726
+
727
+ ### Übersicht
728
+
729
+ | Komponente | Beschreibung | CSS erforderlich |
730
+ | ---------------------------- | ------------------------------------------------------- | ---------------- |
731
+ | **BPMNViewer** | BPMN-Diagramm-Rendering mit Overlays und Markern | Ja |
732
+ | **ProcessInstanceInspector** | Interaktive Prozessinstanz-Ansicht mit Token-Inspektion | Ja |
733
+ | **DynamicUi** | Dynamischer Formular-Builder aus UserTask-Schemas | Ja |
734
+ | **ProcessModelInspector** | Prozessmodell mit Heatmap-Visualisierung | Ja |
735
+ | **DocumentationViewer** | Markdown-Dokumentation mit Syntax-Highlighting | Ja |
736
+ | **SplitterLayout** | Größenveränderbares Panel-Layout | Ja |
737
+ | **DropdownMenu** | Dropdown-Menü (Headless UI) | Ja |
738
+ | **RemoteUserTask** | iFrame-basierte Remote User Task (Common) | Nein |
739
+
740
+ ### BPMNViewer
741
+
742
+ Rendert BPMN-Diagramme und bietet eine Ref-API für Overlays, Marker und Heatmaps.
743
+
744
+ ```typescript
745
+ 'use client';
746
+
747
+ import { BPMNViewerNextJS, BPMNViewerFunctions } from '@5minds/processcube_app_sdk/client';
748
+ import '@5minds/processcube_app_sdk/client/components/BPMNViewer.css';
749
+ import { useRef } from 'react';
750
+
751
+ export default function DiagramPage({ xml }: { xml: string }) {
752
+ const viewerRef = useRef<BPMNViewerFunctions>(null);
753
+
754
+ return (
755
+ <BPMNViewerNextJS
756
+ xml={xml}
757
+ viewerRef={viewerRef}
758
+ onSelectionChanged={(elements) => console.log('Ausgewählt:', elements)}
759
+ onImportDone={() => console.log('Diagramm geladen')}
760
+ />
761
+ );
762
+ }
763
+ ```
764
+
765
+ **Props:**
766
+
767
+ | Prop | Typ | Pflicht | Beschreibung |
768
+ | ----------------------- | ----------------------------------- | ------- | ---------------------------------- |
769
+ | `xml` | `string` | Ja | BPMN-XML des Diagramms |
770
+ | `className` | `string` | Nein | CSS-Klasse für den Container |
771
+ | `preselectedElementIds` | `string[]` | Nein | Vorausgewählte BPMN-Elemente |
772
+ | `onSelectionChanged` | `(elements) => void` | Nein | Callback bei Auswahländerung |
773
+ | `onImportDone` | `() => void` | Nein | Callback nach erfolgreichem Import |
774
+ | `viewerRef` | `ForwardedRef<BPMNViewerFunctions>` | Nein | Nur bei `BPMNViewerNextJS` |
775
+
776
+ **Ref-API (BPMNViewerFunctions):**
777
+
778
+ | Methode | Beschreibung |
779
+ | ------------------------------------ | ----------------------------------------------- |
780
+ | `getOverlays()` | Gibt das Overlay-Modul zurück |
781
+ | `getElementRegistry()` | Gibt die Element-Registry zurück |
782
+ | `addMarker(elementId, className)` | Fügt einen CSS-Marker zu einem Element hinzu |
783
+ | `removeMarker(elementId, className)` | Entfernt einen CSS-Marker |
784
+ | `hasMarker(elementId, className)` | Prüft ob ein Marker gesetzt ist |
785
+ | `showHeatmap(data)` | Zeigt Heatmap-Daten an (`{ elementId: color }`) |
786
+ | `clearHeatmap(data)` | Entfernt Heatmap-Daten |
787
+
788
+ ### ProcessInstanceInspector
789
+
790
+ Interaktive Ansicht einer Prozessinstanz mit BPMN-Diagramm, Token-Inspektion, Retry und Kommandopalette.
791
+
792
+ ```typescript
793
+ 'use client';
794
+
795
+ import { ProcessInstanceInspectorNextJS } from '@5minds/processcube_app_sdk/client';
796
+ import '@5minds/processcube_app_sdk/client/components/ProcessInstanceInspector/ProcessInstanceInspector.css';
797
+ import '@5minds/processcube_app_sdk/client/components/BPMNViewer.css';
798
+
799
+ export default function InspectorPage({ processInstanceId }: { processInstanceId: string }) {
800
+ return (
801
+ <ProcessInstanceInspectorNextJS
802
+ processInstanceId={processInstanceId}
803
+ showFinishTaskButton
804
+ showProcessRetryButton
805
+ showProcessTerminateButton
806
+ showTokenInspectorButton
807
+ onFinish={async ({ flowNodeInstanceId, taskType }) => {
808
+ console.log(`Task ${flowNodeInstanceId} (${taskType}) abgeschlossen`);
809
+ }}
810
+ />
811
+ );
812
+ }
813
+ ```
814
+
815
+ **Props:**
816
+
817
+ | Prop | Typ | Pflicht | Beschreibung |
818
+ | --------------------------------- | ----------------------- | ------- | ------------------------------------- |
819
+ | `processInstanceId` | `string` | Ja | ID der Prozessinstanz |
820
+ | `showFinishTaskButton` | `boolean` | Nein | Play-Button zum Abschließen von Tasks |
821
+ | `showFlowNodeExecutionCount` | `boolean` | Nein | Ausführungszähler auf FlowNodes |
822
+ | `showFlowNodeInstancesListButton` | `boolean` | Nein | Liste der FlowNode-Instanzen |
823
+ | `showGoToFlowNodeButton` | `boolean` | Nein | Navigation zu FlowNodes |
824
+ | `showRetryFlowNodeInstanceButton` | `boolean` | Nein | Retry-Button auf FlowNode-Ebene |
825
+ | `showProcessRefreshButton` | `boolean` | Nein | Daten-Refresh-Button |
826
+ | `showProcessRetryButton` | `boolean` | Nein | Prozess-Retry-Button |
827
+ | `showProcessTerminateButton` | `boolean` | Nein | Prozess-Terminate-Button |
828
+ | `showTokenInspectorButton` | `boolean` | Nein | Token-Inspektor öffnen |
829
+ | `loadingComponent` | `ReactNode` | Nein | Custom Loading-Indikator |
830
+ | `onFinish` | `(taskContext) => void` | Nein | Callback nach Task-Abschluss |
831
+
832
+ ### DynamicUi
833
+
834
+ Rendert dynamische Formulare basierend auf UserTask-FormField-Definitionen. Unterstützt 25+ Feldtypen und Custom Fields.
835
+
836
+ Die Komponente importiert ihr CSS automatisch — ein separater CSS-Import ist nicht nötig.
837
+
838
+ ```typescript
839
+ 'use client';
840
+
841
+ import { DynamicUi } from '@5minds/processcube_app_sdk/client';
842
+
843
+ export default function TaskForm({ task }) {
844
+ return (
845
+ <DynamicUi
846
+ task={task}
847
+ onSubmit={async (result, rawFormData, task) => {
848
+ console.log('Ergebnis:', result);
849
+ }}
850
+ title="Aufgabe bearbeiten"
851
+ />
852
+ );
853
+ }
854
+ ```
855
+
856
+ **Props:**
857
+
858
+ | Prop | Typ | Pflicht | Beschreibung |
859
+ | ----------------------- | -------------------------------------------------------------------------------- | ------- | ---------------------------------------- |
860
+ | `task` | `UserTaskInstance` | Ja | Die User Task mit FormField-Definitionen |
861
+ | `onSubmit` | `(result, formData, task) => Promise<void>` | Ja | Submit-Handler |
862
+ | `headerComponent` | `JSX.Element` | Nein | Custom Header über dem Formular |
863
+ | `className` | `string` | Nein | CSS-Klasse für den Root-Container |
864
+ | `classNames` | `Partial<Record<'wrapper' \| 'base' \| 'header' \| 'body' \| 'footer', string>>` | Nein | CSS-Klassen für Unterelemente |
865
+ | `title` | `ReactNode` | Nein | Titel des Formulars |
866
+ | `customFieldComponents` | `DynamicUiFormFieldComponentMap` | Nein | Custom-Renderer für Feldtypen |
867
+ | `state` | `FormState` | Nein | Externer Formular-State |
868
+ | `onStateChange` | `(newValue, formFieldId, formState) => void` | Nein | Callback bei Wertänderung |
869
+ | `darkMode` | `true` | Nein | Dark-Mode aktivieren |
870
+
871
+ ```mermaid
872
+ graph TD
873
+ Task["UserTaskInstance<br/>(mit FormField-Definitionen)"] --> DynUi["DynamicUi"]
874
+ DynUi --> Fields["FormField-Renderer<br/>(25+ Typen)"]
875
+ Custom["customFieldComponents<br/>(optional)"] --> DynUi
876
+ State["state / onStateChange<br/>(optional)"] --> DynUi
877
+ Fields --> Form["HTML-Formular"]
878
+ Form -->|Submit| Handler["onSubmit(result, formData, task)"]
879
+ ```
880
+
881
+ **Unterstützte Feldtypen:** Boolean, Checkbox, Color, Date, Datetime-Local, Decimal, Email, Enum, File, Header, Hidden, Integer, Month, Paragraph, Password, Radio, Range, Select, Confirm, String, Tel, Textarea, Time, URL, Week, Custom
882
+
883
+ ### Weitere Komponenten
884
+
885
+ #### ProcessModelInspector
886
+
887
+ Zeigt ein Prozessmodell mit optionaler Heatmap-Visualisierung.
888
+
889
+ ```typescript
890
+ import { ProcessModelInspectorNextJS } from '@5minds/processcube_app_sdk/client';
891
+ ```
892
+
893
+ | Prop | Typ | Pflicht | Beschreibung |
894
+ | -------------------------- | ---------------------------------------------------- | ------- | -------------------------- |
895
+ | `processModel` | `any` | Nein | Das Prozessmodell-Objekt |
896
+ | `getInstancesFromDatabase` | `(processModelId, hash, options?) => Promise<any[]>` | Nein | Callback für Heatmap-Daten |
897
+
898
+ #### DocumentationViewer
899
+
900
+ Rendert Markdown-Dokumentation.
901
+
902
+ ```typescript
903
+ import { DocumentationViewer } from '@5minds/processcube_app_sdk/client';
904
+ import '@5minds/processcube_app_sdk/client/components/DocumentationViewer.css';
905
+
906
+ <DocumentationViewer documentation="# Titel\n\nBeschreibung..." />
907
+ ```
908
+
909
+ | Prop | Typ | Pflicht | Beschreibung |
910
+ | --------------- | -------- | ------- | --------------- |
911
+ | `documentation` | `string` | Ja | Markdown-String |
912
+
913
+ #### SplitterLayout
914
+
915
+ Größenveränderbares Zwei-Panel-Layout.
916
+
917
+ ```typescript
918
+ import { SplitterLayout } from '@5minds/processcube_app_sdk/client';
919
+ import '@5minds/processcube_app_sdk/client/components/SplitterLayout.css';
920
+
921
+ <SplitterLayout vertical={false} primaryIndex={0} secondaryMinSize={200}>
922
+ <div>Linkes Panel</div>
923
+ <div>Rechtes Panel</div>
924
+ </SplitterLayout>
925
+ ```
926
+
927
+ | Prop | Typ | Standard | Beschreibung |
928
+ | ---------------------- | ------------------------- | -------- | ---------------------------------- |
929
+ | `vertical` | `boolean` | `false` | Vertikale Teilung |
930
+ | `percentage` | `boolean` | `false` | Größen in Prozent |
931
+ | `primaryIndex` | `number` | `0` | Index des primären Panels |
932
+ | `primaryMinSize` | `number` | `0` | Minimalgröße des primären Panels |
933
+ | `secondaryMinSize` | `number` | `0` | Minimalgröße des sekundären Panels |
934
+ | `secondaryDefaultSize` | `number \| null` | `null` | Standard-Größe |
935
+ | `customClassName` | `string` | `''` | CSS-Klasse |
936
+ | `onSizeChanged` | `(size) => void` | `null` | Callback bei Größenänderung |
937
+ | `onDragStart` | `(prev) => void` | `null` | Callback bei Drag-Start |
938
+ | `onDragEnd` | `(prev, current) => void` | `null` | Callback bei Drag-Ende |
939
+
940
+ #### DropdownMenu
941
+
942
+ Dropdown-Menü basierend auf Headless UI.
943
+
944
+ ```typescript
945
+ import { DropdownMenu, DropdownMenuItem } from '@5minds/processcube_app_sdk/client';
946
+ import '@5minds/processcube_app_sdk/client/components/DropdownMenu.css';
947
+
948
+ <DropdownMenu>
949
+ <DropdownMenuItem title="Bearbeiten" onClick={() => {}} />
950
+ <DropdownMenuItem title="Löschen" onClick={() => {}} isDanger />
951
+ </DropdownMenu>
952
+ ```
953
+
954
+ #### RemoteUserTask (Common)
955
+
956
+ Zeigt eine User Task als iFrame an. Importiert aus dem Common-Modul.
957
+
958
+ ```typescript
959
+ import { RemoteUserTask } from '@5minds/processcube_app_sdk';
960
+
961
+ <RemoteUserTask url="https://my-task-ui.example.com/task/123" />
962
+ ```
963
+
964
+ ## External Tasks
50
965
 
51
966
  External Tasks ermöglichen es, eigene Geschäftslogik in einer Next.js App auszuführen, die von der ProcessCube Engine als Aufgabe vergeben wird. Erreicht ein BPMN-Prozess einen External Service Task, veröffentlicht die Engine diesen unter einem **Topic**. Ein passender Worker in der App holt sich den Task ab, verarbeitet ihn und gibt das Ergebnis zurück.
52
967
 
53
968
  Das App SDK übernimmt dabei die komplette Infrastruktur: Worker-Prozesse werden automatisch gestartet, überwacht und bei Fehlern neu gestartet. Der Entwickler schreibt nur die eigentliche Handler-Funktion.
54
969
 
55
- #### Architektur
970
+ ### Architektur
56
971
 
57
972
  Das folgende Diagramm zeigt die drei beteiligten Schichten und ihre Kommunikation:
58
973
 
@@ -91,7 +1006,7 @@ graph LR
91
1006
  | **ExternalTaskWorkerProcess** | Eigenständiger Node.js-Kindprozess (einer pro Topic). Lädt den transpilierten Handler, verbindet sich per HTTP-Long-Polling mit der Engine und verarbeitet Tasks. |
92
1007
  | **ProcessCube Engine** | Verwaltet BPMN-Prozesse und vergibt External Tasks an Worker über das Fetch-and-Lock-Protokoll. |
93
1008
 
94
- #### Lebenszyklus eines External Tasks
1009
+ ### Lebenszyklus eines External Tasks
95
1010
 
96
1011
  Das folgende Sequenzdiagramm zeigt, wie ein External Task von der Engine zum Worker gelangt, verarbeitet und abgeschlossen wird:
97
1012
 
@@ -130,7 +1045,7 @@ sequenceDiagram
130
1045
  4. Während der Verarbeitung verlängert der Worker automatisch den Lock, damit die Engine den Task nicht vorzeitig freigibt.
131
1046
  5. Nach Abschluss meldet der Worker das Ergebnis (Finish) oder einen Fehler (Error) an die Engine.
132
1047
 
133
- #### Worker-Startup und IPC-Kommunikation
1048
+ ### Worker-Startup und IPC-Kommunikation
134
1049
 
135
1050
  Das App SDK startet pro `external_task.ts`-Datei einen eigenen Node.js-Kindprozess. Die Kommunikation zwischen Hauptprozess (Adapter) und Kindprozess (Worker) läuft über IPC (Inter-Process Communication):
136
1051
 
@@ -179,7 +1094,7 @@ sequenceDiagram
179
1094
  | `restart` | Adapter → Worker | Hot-Reload: Stoppt den alten Worker und startet mit neuem Code (gleiche Worker-ID) |
180
1095
  | `updateIdentity` | Adapter → Worker | Aktualisiert den Auth-Token auf dem laufenden Worker |
181
1096
 
182
- #### Fehlerbehandlung und Restart-Strategie
1097
+ ### Fehlerbehandlung und Restart-Strategie
183
1098
 
184
1099
  Das System hat zwei Ebenen der Fehlerbehandlung: im Worker-Prozess selbst und im Adapter (Hauptprozess).
185
1100
 
@@ -229,17 +1144,17 @@ flowchart TD
229
1144
  - Wird das Limit erreicht, bleibt der Worker gestoppt — ein manueller Eingriff (z.B. App-Neustart) ist nötig.
230
1145
  - Nach Ablauf des 5-Minuten-Fensters wird der Zähler zurückgesetzt.
231
1146
 
232
- #### Setup und Konfiguration
1147
+ ### Setup und Konfiguration
233
1148
 
234
- ##### 1. Next.js Plugin aktivieren
1149
+ #### 1. Next.js Plugin aktivieren
235
1150
 
236
- In der `next.config.js` wird das SDK-Plugin eingebunden und External Tasks aktiviert:
1151
+ In der `next.config.ts` wird das SDK-Plugin eingebunden und External Tasks aktiviert:
237
1152
 
238
- ```javascript
239
- // next.config.js
240
- const { withApplicationSdk } = require('@5minds/processcube_app_sdk/server');
1153
+ ```typescript
1154
+ // next.config.ts
1155
+ import { withApplicationSdk } from '@5minds/processcube_app_sdk/server';
241
1156
 
242
- module.exports = withApplicationSdk({
1157
+ export default withApplicationSdk({
243
1158
  applicationSdk: {
244
1159
  useExternalTasks: true,
245
1160
  // Optional: Eigenes Verzeichnis für External Tasks
@@ -250,7 +1165,7 @@ module.exports = withApplicationSdk({
250
1165
 
251
1166
  Das Plugin erkennt automatisch, ob die App im Development- oder Production-Modus läuft, und startet die Worker entsprechend. Während des Build-Prozesses (`next build`) werden keine Worker gestartet.
252
1167
 
253
- ##### 2. Handler-Datei anlegen
1168
+ #### 2. Handler-Datei anlegen
254
1169
 
255
1170
  External Tasks werden durch Dateien mit dem Namen `external_task.ts` (oder `.js`) definiert. Das Verzeichnis, in dem die Datei liegt, bestimmt automatisch das **Topic**, unter dem sich der Worker bei der Engine registriert.
256
1171
 
@@ -271,7 +1186,7 @@ Das SDK sucht Handler-Dateien standardmäßig in `./app` oder `./src/app`. Ein e
271
1186
 
272
1187
  > **Wichtig:** Pro Verzeichnis darf nur eine `external_task.ts` oder `external_task.js` existieren. Beide Dateien im selben Verzeichnis führen zu einem Fehler.
273
1188
 
274
- #### Handler-Signatur
1189
+ ### Handler-Signatur
275
1190
 
276
1191
  Der Handler wird als **Default-Export** der Datei definiert. Er erhält bis zu drei Parameter:
277
1192
 
@@ -290,7 +1205,7 @@ export default async function handleExternalTask(payload: any, task: ExternalTas
290
1205
 
291
1206
  **Rückgabewert:** Das zurückgegebene Objekt wird als Ergebnis an die Engine gemeldet und steht im BPMN-Prozess als Variable zur Verfügung.
292
1207
 
293
- #### Worker-Konfiguration
1208
+ ### Worker-Konfiguration
294
1209
 
295
1210
  Über einen benannten `config`-Export können Worker-Einstellungen pro Handler angepasst werden:
296
1211
 
@@ -308,7 +1223,7 @@ export const config: ExternalTaskConfig = {
308
1223
  | `lockDuration` | `number` | `30000` | Dauer in Millisekunden, für die ein Task gesperrt wird. Bestimmt auch das Intervall der Lock-Verlängerung und die maximale Verzögerung bei Abort-Signalen. |
309
1224
  | `maxTasks` | `number` | `10` | Maximale Anzahl gleichzeitig abgeholter Tasks pro Polling-Zyklus. |
310
1225
 
311
- #### Abort-Handling bei Boundary Events
1226
+ ### Abort-Handling bei Boundary Events
312
1227
 
313
1228
  Wenn ein BPMN Boundary Event (z.B. ein Timer oder Signal) einen External Task abbricht, löst die Engine den Abbruch beim nächsten Lock-Renewal aus. Das `AbortSignal` im Handler wird daraufhin ausgelöst.
314
1229
 
@@ -354,7 +1269,7 @@ export default async function handleExternalTask(payload: any, _task: any, signa
354
1269
  }
355
1270
  ```
356
1271
 
357
- #### Authentifizierung und Token-Management
1272
+ ### ETW-Authentifizierung und Token-Management
358
1273
 
359
1274
  Ist eine ProcessCube Authority konfiguriert, holt der Adapter automatisch Tokens per **OpenID Connect Client Credentials Grant** und verteilt sie an alle Worker.
360
1275
 
@@ -386,17 +1301,7 @@ sequenceDiagram
386
1301
  - Der periodische Token-Refresh versucht es **unbegrenzt** mit Backoff (max. 60s).
387
1302
  - Ist keine Authority konfiguriert, wird eine Dummy-Identity verwendet (für lokale Entwicklung ohne Auth).
388
1303
 
389
- #### Umgebungsvariablen
390
-
391
- | Variable | Pflicht | Standard | Beschreibung |
392
- | ------------------------------------------------ | -------------- | ------------------------ | ---------------------------------------------------------------------------------------- |
393
- | `PROCESSCUBE_ENGINE_URL` | Nein | `http://localhost:10560` | URL der ProcessCube Engine |
394
- | `PROCESSCUBE_AUTHORITY_URL` | Nein | — | URL des OpenID-Providers. Wenn gesetzt, wird Token-basierte Authentifizierung aktiviert. |
395
- | `PROCESSCUBE_EXTERNAL_TASK_WORKER_CLIENT_ID` | Wenn Authority | — | Client-ID für den OpenID Client Credentials Grant |
396
- | `PROCESSCUBE_EXTERNAL_TASK_WORKER_CLIENT_SECRET` | Wenn Authority | — | Client-Secret für den OpenID Client Credentials Grant |
397
- | `PROCESSCUBE_APP_SDK_ETW_RETRY` | Nein | `6` | Maximale Anzahl der Reconnect-Versuche im Worker-Prozess bei Verbindungsfehlern |
398
-
399
- #### Vollständiges Beispiel
1304
+ ### Vollständiges External-Task-Beispiel
400
1305
 
401
1306
  Eine `external_task.ts` mit allen Features — Konfiguration, typisiertem Payload, Fehlerbehandlung und Abort-Support:
402
1307
 
@@ -451,44 +1356,70 @@ export default async function handleExternalTask(payload: OrderPayload, task: an
451
1356
  }
452
1357
  ```
453
1358
 
454
- #### Hot-Reload
1359
+ ### Hot-Reload
455
1360
 
456
1361
  Im Development-Modus überwacht das SDK die Handler-Dateien per File-Watcher. Änderungen an einer `external_task.ts` werden automatisch erkannt: Die Datei wird neu transpiliert und der Worker per IPC-Nachricht (`restart`) mit dem neuen Code neu gestartet — ohne die App neu starten zu müssen. Die Worker-ID bleibt dabei erhalten.
457
1362
 
458
- ## Wie kann ich das Projekt aufsetzen?
1363
+ ## Entwicklung
459
1364
 
460
- ### Setup/Installation
1365
+ ### Setup
461
1366
 
462
- Das SDK wird über den Node Paketmanager `npm` gebaut.
1367
+ Das SDK wird über `npm` gebaut:
463
1368
 
464
- Für das Installieren und Bauen können folgende Befehle benutzt werden:
465
-
466
- ```shell
1369
+ ```bash
467
1370
  npm ci
468
1371
  npm run build
469
1372
  ```
470
1373
 
471
- Für ein Productionbuild:
1374
+ Für ein Production-Build:
472
1375
 
473
- ```shell
1376
+ ```bash
474
1377
  npm run build:prod
475
1378
  ```
476
1379
 
477
- Um mit dem Paket lokal zu arbeiten, kann es mit npm in ein anderes Projekt verlinkt werden:
1380
+ ### Verfügbare Befehle
1381
+
1382
+ | Befehl | Beschreibung |
1383
+ | ---------------------- | ----------------------------------------------- |
1384
+ | `npm run build` | Development-Build (Code + Types + CSS parallel) |
1385
+ | `npm run build:prod` | Production-Build (clean + minify + tree-shake) |
1386
+ | `npm run build:types` | Nur `.d.ts`-Dateien generieren |
1387
+ | `npm run watch` | Watch-Modus (alle Build-Prozesse) |
1388
+ | `npm run format` | Code mit Prettier formatieren |
1389
+ | `npm run format:check` | Formatierung prüfen |
1390
+ | `npm run clean` | `build/`-Verzeichnis löschen |
1391
+
1392
+ ### Lokale Entwicklung mit npm link
478
1393
 
479
- ```shell
1394
+ Um das SDK lokal in einer Consumer-App zu testen:
1395
+
1396
+ ```bash
1397
+ # Im SDK-Verzeichnis
480
1398
  npm link
481
1399
  npm run watch
1400
+
1401
+ # Im Zielprojekt
1402
+ npm link @5minds/processcube_app_sdk
482
1403
  ```
483
1404
 
484
- Im Zielprojekt anschließend:
1405
+ Bei Problemen mit React (doppelte React-Instanz):
485
1406
 
486
- ```shell
487
- npm link @5minds/processcube_app_sdk
1407
+ ```bash
1408
+ npm link <pfad-zum-zielprojekt>/node_modules/react
488
1409
  ```
489
1410
 
490
- Bei Problemen mit React muss ggf. noch die React Dependency des Zielprojekts zurück in das SDK gelinkt werden, damit nur eine React Instanz zur Laufzeit existiert:
1411
+ ### Test-App
1412
+
1413
+ Im Verzeichnis `test-app/` liegt eine Next.js-Beispielanwendung:
1414
+
1415
+ ```bash
1416
+ cd test-app
491
1417
 
492
- ```shell
493
- npm link <path-to-project>/node_modules/react
1418
+ # Docker-Infrastruktur starten (Engine, Authority, PostgreSQL)
1419
+ docker compose up
1420
+
1421
+ # App starten
1422
+ npm run dev
494
1423
  ```
1424
+
1425
+ Die Test-App enthält drei External Task Handler (`test-task`, `doit`, `dothis`) und BPMN-Beispielprozesse.