@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 +999 -68
- package/build/client/{actions-MB5VDCO7.mjs → actions-AYWPNATG.mjs} +1 -1
- package/build/client/components/DynamicUi/DynamicUi.d.ts +1 -0
- package/build/client/index.cjs +2 -2
- package/build/client/index.css +1 -1
- package/build/client/index.mjs +3 -3
- package/build/server/index.cjs +1 -1
- package/build/server/index.mjs +1 -1
- package/build/server/lib/AuthorityClient.d.ts +72 -0
- package/build/server/lib/getServerIdentity.d.ts +44 -0
- package/build/server/lib/index.d.ts +2 -0
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -1,58 +1,973 @@
|
|
|
1
|
-
# ProcessCube
|
|
1
|
+
# ProcessCube App SDK
|
|
2
2
|
|
|
3
|
-
Das
|
|
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
|
-
##
|
|
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
|
-
-
|
|
74
|
+
- Node.js >= 24
|
|
75
|
+
- Next.js >= 15
|
|
76
|
+
- React >= 19
|
|
10
77
|
|
|
11
|
-
|
|
12
|
-
|
|
78
|
+
### Paket installieren
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npm install @5minds/processcube_app_sdk
|
|
13
82
|
```
|
|
14
83
|
|
|
15
|
-
|
|
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
|
-
|
|
92
|
+
export default withApplicationSdk({
|
|
93
|
+
applicationSdk: {
|
|
94
|
+
useExternalTasks: true,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
18
98
|
|
|
19
|
-
|
|
99
|
+
Ohne External Tasks reicht:
|
|
20
100
|
|
|
21
|
-
|
|
101
|
+
```typescript
|
|
102
|
+
// next.config.ts
|
|
103
|
+
import type { NextConfig } from 'next';
|
|
22
104
|
|
|
23
|
-
|
|
105
|
+
const nextConfig: NextConfig = {
|
|
106
|
+
serverExternalPackages: ['esbuild'],
|
|
107
|
+
};
|
|
24
108
|
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
482
|
+
#### getActiveProcessInstances
|
|
30
483
|
|
|
31
|
-
|
|
484
|
+
Gibt alle laufenden Prozessinstanzen zurück. Unterstützt Filterung und Paginierung.
|
|
32
485
|
|
|
33
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
586
|
+
const { userTasks } = await getWaitingUserTasksByProcessInstanceId('process-instance-id');
|
|
44
587
|
|
|
45
|
-
|
|
46
|
-
|
|
588
|
+
// Auch mit Array von IDs
|
|
589
|
+
const { userTasks: multiple } = await getWaitingUserTasksByProcessInstanceId(['id-1', 'id-2']);
|
|
47
590
|
```
|
|
48
591
|
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1147
|
+
### Setup und Konfiguration
|
|
233
1148
|
|
|
234
|
-
|
|
1149
|
+
#### 1. Next.js Plugin aktivieren
|
|
235
1150
|
|
|
236
|
-
In der `next.config.
|
|
1151
|
+
In der `next.config.ts` wird das SDK-Plugin eingebunden und External Tasks aktiviert:
|
|
237
1152
|
|
|
238
|
-
```
|
|
239
|
-
// next.config.
|
|
240
|
-
|
|
1153
|
+
```typescript
|
|
1154
|
+
// next.config.ts
|
|
1155
|
+
import { withApplicationSdk } from '@5minds/processcube_app_sdk/server';
|
|
241
1156
|
|
|
242
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
1363
|
+
## Entwicklung
|
|
459
1364
|
|
|
460
|
-
### Setup
|
|
1365
|
+
### Setup
|
|
461
1366
|
|
|
462
|
-
Das SDK wird über
|
|
1367
|
+
Das SDK wird über `npm` gebaut:
|
|
463
1368
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
```shell
|
|
1369
|
+
```bash
|
|
467
1370
|
npm ci
|
|
468
1371
|
npm run build
|
|
469
1372
|
```
|
|
470
1373
|
|
|
471
|
-
Für ein
|
|
1374
|
+
Für ein Production-Build:
|
|
472
1375
|
|
|
473
|
-
```
|
|
1376
|
+
```bash
|
|
474
1377
|
npm run build:prod
|
|
475
1378
|
```
|
|
476
1379
|
|
|
477
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1405
|
+
Bei Problemen mit React (doppelte React-Instanz):
|
|
485
1406
|
|
|
486
|
-
```
|
|
487
|
-
npm link
|
|
1407
|
+
```bash
|
|
1408
|
+
npm link <pfad-zum-zielprojekt>/node_modules/react
|
|
488
1409
|
```
|
|
489
1410
|
|
|
490
|
-
|
|
1411
|
+
### Test-App
|
|
1412
|
+
|
|
1413
|
+
Im Verzeichnis `test-app/` liegt eine Next.js-Beispielanwendung:
|
|
1414
|
+
|
|
1415
|
+
```bash
|
|
1416
|
+
cd test-app
|
|
491
1417
|
|
|
492
|
-
|
|
493
|
-
|
|
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.
|