Eviworx
Docs

Changes API

Die Changes API verwaltet IT-Änderungen nach ITIL: Status-Maschine mit dedizierten Transition-Endpoints, Genehmigung über das Unified-Approval-Framework, strukturierte Change-Tasks (Implementation/Test/Rollback) mit individueller oder Gruppen-Zuweisung sowie Kalender-Einladungen (.ics) für geplante Arbeiten.

🔄
Funktionen
✓ Statuswechsel über 10 Transition-Endpoints
✓ Zentrale Genehmigung (/api/approvals/:id/decide)
✓ 4-Augen-Prinzip erzwungen
✓ Change-Tasks (IMPLEMENTATION/TEST/ROLLBACK)
✓ Task-Zuweisung an Person oder Gruppe (XOR)
✓ 4 Change-Typen (STANDARD, NORMAL …)
✓ Rollback-Flow (ROLLING_BACK → BACKED_OUT)
✓ Versionierte Templates (ITIL Standard Changes)
✓ Kalender-Einladungen für geplante Tasks (.ics)
✓ Feld-Berechtigungen pro Status (field-permissions)

Endpoints Übersicht

Method Endpoint Beschreibung
GET/api/changesListe mit Filtern ({data, pagination}; RBAC-gefiltert)
GET/api/changes/statsTab-Zähler (all / my / assigned) — akzeptiert dieselben Filter wie die Liste
GET/api/changes/:idEinzelnes Change (per ID oder Nummer)
POST/api/changesNeues Change erstellen (Status immer DRAFT) → 201
PATCH/api/changes/:idChange-Felder aktualisieren (KEIN Status, version Pflicht)
DELETE/api/changes/:idChange löschen (Soft-Delete, kritische Aktion)
POST/api/changes/:id/restoreGelöschtes Change wiederherstellen (Papierkorb-Liste: ?deleted=1)
PATCH/api/changes/:id/assignChange Manager setzen/entfernen → {change, assignmentChanged}
GET/api/changes/:id/field-permissionsEditierbare/gesperrte/erforderliche Felder + erlaubte Transitions für aktuellen Status
POST/api/changes/:id/activityKommentar hinzufügen (Activity-Log selbst kommt über GET /:id)

Enum-Werte in Großschreibung: Status, Typ, Priorität, Risiko, Impact und Dringlichkeit werden in Großschreibung gesendet und geliefert (NORMAL, VERY_HIGH, PENDING_APPROVAL …), auch in Filtern und Sortierung. Kleingeschriebene Werte ergeben 400.

Wer den Change sieht: Neben Antragsteller (viewOwn) und globaler Sicht (viewAll) öffnet auch die Beteiligung den Zugang: zugewiesener Change Manager, offene Genehmigung sowie, wer einen Change-Task trägt (direkt, über die zugewiesene Gruppe oder als Vertretung) und changes.viewOwn bzw. viewPendingApprovals hat. Das wirkt in Liste, Detail, Suche, Berichten, Anhängen und den Verknüpfungs-Karten. Bearbeitungs- und Task-Verwaltungsrechte bleiben davon unberührt. Ohne eines der Rechte viewAll, viewOwn oder viewPendingApprovals antworten Liste und Kennzahlen 403.

Transition-Endpoints (Status-Wechsel)

Wichtig: Status werden ausschließlich über diese dedizierten Endpoints gesetzt. PATCH /api/changes/:id akzeptiert KEIN status-Feld. Jeder Endpoint hat eine eigene Permission und Pflichtfelder im Body.

Endpoint Transition Permission Body
POST /:id/submitDRAFT → SUBMITTEDchanges.submitchangeManagerId, notes?
POST /:id/route-to-approvalSUBMITTED → PENDING_APPROVAL (oder APPROVED bei skipApproval)changes.manageWorkflow + zugewiesener Change ManagerskipApproval?, notes?
POST /:id/scheduleAPPROVED → SCHEDULEDchanges.schedulescheduledStartTime, scheduledEndTime
POST /:id/start-implementationSCHEDULED → IN_PROGRESSchanges.startImplementationnotes?
POST /:id/completeIN_PROGRESS → COMPLETEDchanges.markCompletedresolution (≥20), closerId, actualEndTime?
POST /:id/failIN_PROGRESS → FAILEDchanges.markFailedresolution (≥20), closerId, backoutPerformed?
POST /:id/initiate-rollbackIN_PROGRESS → ROLLING_BACKchanges.backoutreason (≥20)
POST /:id/backoutROLLING_BACK → BACKED_OUTchanges.backoutresolution (≥20), closerId
POST /:id/closeCOMPLETED/FAILED/BACKED_OUT → CLOSEDchanges.closereviewNotes (≥20), successCriteriaMet?
POST /:id/return-to-draft* → DRAFTchanges.returnToDraftreason (≥10)

Fehler beim Routen zur Genehmigung: Ein STANDARD-Change braucht keine Genehmigungsrunde; der Versuch ergibt 400 CHANGE_APPROVAL_NOT_REQUIRED. Vorgesehen ist hier skipApproval: true. Findet sich kein verfügbarer Genehmiger, antwortet die Route mit 400 CHANGE_NO_APPROVERS_AVAILABLE.

Vollständiger Task-Satz als Voraussetzung: Die Lifecycle-Übergänge verlangen bis zum Abschluss den vollständigen Satz an Change-Tasks (je ein Task der Arten IMPLEMENTATION, TEST und ROLLBACK). Ein Change ohne Tasks lässt sich weder starten noch schließen — der Rückweg ist return-to-draft.

Approval-Endpoints

Method Endpoint Beschreibung
POST/api/changes/:id/approversApprover zuweisen (legt einen Genehmigungseintrag an)
POST/api/approvals/:id/decideApprover-Entscheidung (Unified Approval Framework)

Entscheidungen (approve/reject) trifft der Genehmiger über die Approvals API. Siehe Approvals API.

Change-Tasks

Alle Routen liegen unter /api/changes/:changeId/tasks:

Method Endpoint Beschreibung
GET/Tasks des Changes auflisten
POST/Task erstellen
POST/reorderReihenfolge ändern (pro kind, mit version)
POST/bulk-assignMehrere Tasks zuweisen
POST/bulk-skipMehrere Tasks überspringen
POST/bulk-deleteMehrere Tasks löschen
PATCH/:taskIdTask aktualisieren (version Pflicht)
DELETE/:taskId?version=NTask löschen (version als Query-Param)
POST/:taskId/assignPerson ODER Gruppe zuweisen
POST/:taskId/startTask starten (→ IN_PROGRESS)
POST/:taskId/completeTask abschließen (completionNote Pflicht)
POST/:taskId/skipTask überspringen (skipReason Pflicht)
POST/:taskId/failTask als fehlgeschlagen markieren (failureReason Pflicht, ≥10 Zeichen)
POST/:taskId/retryFehlgeschlagenen Task erneut aufnehmen (nur aus FAILED, Begründung ≥10 Zeichen)
POST/:taskId/commentsKommentar zum Task (≥10 Zeichen) → 201

Change Templates /api/changes/templates

Templates bilden wiederkehrende Standard-Changes (ITIL) ab: vordefinierte Standardwerte, gesperrte bzw. vom Anwender auszufüllende Felder und ein eigenes Task-Set. Templates sind versioniert und durchlaufen einen eigenen Genehmigungs-Workflow. Aus einem genehmigten Template werden Changes erzeugt — das Task-Set wird dabei aus dem genehmigten Versions-Snapshot geklont.

Template-Status

DRAFT → SUBMITTED(submit) → PENDING_APPROVAL → APPROVED → RETIRED(retire)

Nebenwege:PENDING_APPROVAL → DRAFT     (withdraw)
APPROVED         → DRAFT      (new-version — neue Entwurfs-Version)
DRAFT(verworfen) → APPROVED  (discard-draft — zurück zur letzten genehmigten Version)

Bearbeiten (PATCH, Tasks) ist nur im Status DRAFT möglich.Genehmigen und Ablehnen läuft über das Unified-Approval-Framework.

Endpoints

Method Endpoint Beschreibung Permission
GET/templatesListe (Filter + offset/limit-Pagination)changes.viewTemplates
GET/templates/approvedNur genehmigte Templates (für Auswahl)changes.viewTemplates
GET/templates/statisticsTemplate-Statistikchanges.viewTemplates
GET/templates/:idEinzelnes Templatechanges.viewTemplates
GET/templates/:id/versionsVersionshistoriechanges.viewTemplates
GET/templates/:id/versions/:versionBestimmte Versionchanges.viewTemplates
GET/templates/:id/changesChanges, die dieses Template nutzen (limit/offset)changes.viewTemplates
GET/templates/:id/activityActivity-Historie (limit)changes.viewTemplates
GET/templates/:id/tasksTemplate-Tasks auflistenchanges.viewTemplates
POST/templatesTemplate erstellen (201, Status DRAFT)changes.createTemplates
PATCH/templates/:idTemplate aktualisieren (nur DRAFT)changes.editOwnTemplates / editAllTemplates
DELETE/templates/:idTemplate löschen (nur DRAFT, 204)changes.deleteTemplates
POST/templates/:id/submitDRAFT → PENDING_APPROVALchanges.submitTemplates
POST/templates/:id/withdrawPENDING_APPROVAL → DRAFT zurückziehenchanges.submitTemplates
POST/templates/:id/discard-draftDRAFT verwerfen → letzte genehmigte Versionchanges.editOwnTemplates / editAllTemplates
POST/templates/:id/retire→ RETIRED (Body reason?)changes.retireTemplates
POST/templates/:id/new-versionAPPROVED → neue DRAFT-Version (Body changeReason + Felder)changes.editOwnTemplates / editAllTemplates
POST/templates/:id/create-changeChange aus Template erstellen (201)changes.create
POST/templates/:id/tasksTemplate-Task anlegen (nur DRAFT, 201)changes.editOwnTemplates / editAllTemplates
PATCH/templates/:id/tasks/:taskIdTemplate-Task ändern (nur DRAFT)changes.editOwnTemplates / editAllTemplates
DELETE/templates/:id/tasks/:taskIdTemplate-Task löschen (nur DRAFT, 204)changes.editOwnTemplates / editAllTemplates
POST/templates/:id/tasks/reorderTask-Reihenfolge ändern (nur DRAFT, 204)changes.editOwnTemplates / editAllTemplates

Schreib-/Aktions-Routen prüfen zusätzlich Ownership (Ersteller ODER editAllTemplates). Ein Template im Status DRAFT ist nur für seinen Ersteller sichtbar — es sei denn, er trägt changes.viewDraftTemplates ODER es existiert bereits eine genehmigte Version: dann zeigt die Vorlage ihre genehmigte Fassung jedem viewTemplates-Träger. Dieselbe Regel gilt für Liste, Detail und die Unterrouten (/versions, /changes, /activity, /tasks); ein Template außerhalb der eigenen Sicht liefert 404 TEMPLATE_NOT_FOUND, genau wie ein nicht existierendes. Genehmigung/Ablehnung läuft ausschließlich über Approvals API (POST /api/approvals/:id/decide).

Template-Felder

Feld Typ Beschreibung
namestringSlug, Pflicht (nur a–z, 0–9, Bindestrich)
displayNamestringAnzeigename, Pflicht
descriptionstringBeschreibung, Pflicht
typeenumSTANDARD, NORMAL, EMERGENCY, MAJOR (Default STANDARD)
categoryIdstring?Change-Kategorie
defaultTitle / defaultDescription / defaultJustificationstring?Vorbelegte Inhalte des erzeugten Changes
defaultRiskLevel / defaultImpactenumLOW, MEDIUM, HIGH, VERY_HIGH (Default LOW)
defaultUrgency / defaultPriorityenumLOW, MEDIUM, HIGH, CRITICAL (Default LOW)
defaultRiskAssessmentany?Vorbelegte Risikobewertung
defaultAffectedServices / defaultAffectedAssetsstring[]Vorbelegte Betroffenheiten
defaultPlannedDurationnumber?Vorbelegte geplante Dauer (Minuten)
lockedFieldsstring[]Beim Erstellen aus dem Template gesperrte Felder
requiredUserFieldsstring[]Felder, die der Anwender beim Erstellen ausfüllen muss

Pagination der Template-Flächen: Die Template-Liste und die Liste der Changes eines Templates nutzen offset/limit-Pagination (Default 20, maximal 100), die Activity-Historie Default 50 / maximal 100 — anders als die Change-Liste (page/per). Die Enum-Werte sind hier wie überall in Großschreibung.

Template-Tasks

Template-Tasks definieren das Task-Set, das beim Erstellen eines Changes geklont wird. Verwaltbar nur, solange das Template im DRAFT ist.

Feld Werte Beschreibung
kindIMPLEMENTATION, TEST, ROLLBACKArt (nach Erstellung nicht änderbar — löschen + neu)
phasePREP, EXECUTE, VALIDATE, POSTCHECKPhase (Default EXECUTE)
title / descriptionstringTitel (Pflicht) / Beschreibung
sortOrdernumberReihenfolge
estimatedMinutesnumber?Geschätzte Dauer
requiredPermissionstring?Beim Ausführen geforderte Permission
roleHintstring?Hinweis auf zuständige Rolle
suggestedGroupIdstring?Vorgeschlagene Agent-Gruppe
dependsOnTemplateTaskIdscuid[]Vorgänger-Template-Tasks

Change aus Template erstellen

POST /api/changes/templates/:id/create-change
{
  "title": "Upgrade PostgreSQL on cluster-prod-2",
  "scheduledStartTime": "2026-02-01T02:00:00Z",
  "scheduledEndTime": "2026-02-01T04:00:00Z",
  "assignedGroupId": "clx-dba-group-id"
}

Alle Body-Felder sind optional und überschreiben die Template-Defaults: title, description, justification, affectedServices, affectedAssets, scheduledStartTime, scheduledEndTime, plannedDuration, categoryId, assignedToId, assignedGroupId (per API-Key zusätzlich requestorId). Gesperrte Felder (lockedFields) bleiben unverändert; das Task-Set wird aus dem genehmigten Versions-Snapshot geklont.

Change-Kategorien

Method Endpoint Beschreibung
GET/api/changes/categoriesAlle Kategorien
POST/api/changes/categoriesKategorie erstellen
PUT/api/changes/categories/:idKategorie aktualisieren
DELETE/api/changes/categories/:idKategorie löschen

Status-Maschine

Changes durchlaufen 12 Status. Jeder Übergang erfolgt über einen dedizierten Transition-Endpoint:

DRAFT → SUBMITTED → PENDING_APPROVAL → APPROVED → SCHEDULED → IN_PROGRESS → COMPLETED → CLOSED

Alternative Pfade:
PENDING_APPROVAL → REJECTED            (Approver lehnt ab)
*                → DRAFT               (via return-to-draft)
IN_PROGRESS      → FAILED              (via fail)
IN_PROGRESS      → ROLLING_BACK → BACKED_OUT  (via initiate-rollback + backout)
COMPLETED/FAILED/BACKED_OUT → CLOSED   (via close)

Status-Beschreibung:
• DRAFT            = Entwurf, noch nicht eingereicht
• SUBMITTED        = Eingereicht, Change Manager gesetzt
• PENDING_APPROVAL = Wartet auf Approvals (Unified-Approval-Framework)
• APPROVED         = Genehmigt
• REJECTED         = Abgelehnt
• SCHEDULED        = Für Wartungsfenster geplant
• IN_PROGRESS      = Umsetzung läuft (Change-Tasks werden abgearbeitet)
• ROLLING_BACK     = Rollback wird durchgeführt
• COMPLETED        = Erfolgreich abgeschlossen
• FAILED           = Fehlgeschlagen
• BACKED_OUT       = Zurückgerollt
• CLOSED           = Geschlossen & archiviert

Change-Typen

Typ Beschreibung Approval-Anforderung
STANDARD Routine-Änderungen, geringes Risiko (oft Template-basiert) Häufig vorab genehmigt
NORMAL Standard-Änderungen, mittleres Risiko Regulärer Approval-Prozess
EMERGENCY Notfall-Änderungen (z. B. dringende Sicherheitsupdates) Fast-Track, Post-Implementation-Review
MAJOR Große Änderungen, hohes Risiko Erweiterte Approvals

Change erstellen

Request

POST /api/changes

Antragsteller (requestorId): Bei einem angemeldeten Benutzer setzt der Server den Antragsteller auf den Aufrufer selbst; ein im Body mitgeschickter Wert wird ignoriert. Nur API-Key-Zugriffe müssen requestorId angeben. Der Status ist beim Anlegen immer DRAFT; alles Weitere läuft über die Transition-Endpoints.

{
  "title": "Upgrade PostgreSQL to version 17",
  "description": "Upgrade production database from PostgreSQL 16 to 17 for performance and security.",
  "justification": "Security patches for CVE-2024-xxx. Performance improvements.",
  "type": "NORMAL",
  "categoryId": "clx-category-id",
  "priority": "HIGH",
  "riskLevel": "MEDIUM",
  "impact": "HIGH",
  "urgency": "MEDIUM",
  "scheduledStartTime": "2026-02-01T02:00:00Z",
  "scheduledEndTime": "2026-02-01T04:00:00Z",
  "plannedDuration": 120,
  "affectedServices": ["Database", "API"],
  "affectedAssets": ["clx-asset-id"],
  "riskAssessment": "Standard maintenance-window upgrade, rollback tested.",
  "assignedToId": "clx-change-manager-id",
  "tasks": [
    { "clientKey": "impl-1", "kind": "IMPLEMENTATION", "phase": "EXECUTE", "title": "Run pg_upgrade" },
    { "kind": "TEST", "phase": "VALIDATE", "title": "Run integration tests", "dependsOnTaskKeys": ["impl-1"] },
    { "kind": "ROLLBACK", "phase": "POSTCHECK", "title": "Restore from backup if needed" }
  ]
}

Response (201 Created)

{
  "id": "clx...",
  "number": "CHG-2026-000042",
  "title": "Upgrade PostgreSQL to version 17",
  "status": "DRAFT",
  "type": "NORMAL",
  "priority": "HIGH",
  "riskLevel": "MEDIUM",
  "impact": "HIGH",
  "urgency": "MEDIUM",
  "requestor": { "id": "clx...", "name": "John Doe", "email": "john@example.com" },
  "assignedTo": { "id": "clx...", "name": "Change Manager" },
  "createdAt": "2026-01-27T15:00:00.000Z"
}

Felder-Übersicht

Feld Typ Pflicht? Beschreibung
titlestringKurztitel (5–200 Zeichen)
descriptionstringDetaillierte Beschreibung (20–5000 Zeichen)
justificationstringBegründung für den Change (20–2000 Zeichen)
typeenumSTANDARD, NORMAL, EMERGENCY, MAJOR
categoryIdstringChange-Kategorie (ID, Pflichtfeld)
priorityenumLOW, MEDIUM, HIGH, URGENT, CRITICAL
riskLevelenumLOW, MEDIUM, HIGH, VERY_HIGH
impactenumLOW, MEDIUM, HIGH, VERY_HIGH
urgencyenumLOW, MEDIUM, HIGH, CRITICAL
requestorIdstring(API-Key)Bei User-Auth = eingeloggter User; bei API-Key Pflicht
tasksarrayInline Change-Tasks (siehe Change-Tasks); nicht zusammen mit templateId
scheduledStartTimeDateTimeGeplanter Start
scheduledEndTimeDateTimeGeplantes Ende
plannedDurationnumberGeplante Dauer/Downtime (Minuten)
affectedServicesstring[]Betroffene Services
affectedAssetsstring[]Betroffene Assets
riskAssessmentstringRisikobewertung (Freitext)
assignedToId / assignedGroupIdstringChange Manager (Person oder Gruppe)
relatedTickets / relatedProblemsstring[]Verlinkte Tickets/Problems — verlangen das Verknüpfungs-Recht und die Sicht auf die Gegenseite, nur mit Benutzeranmeldung
templateIdstringTemplate-Referenz (Tasks werden aus Snapshot geklont)
fromProblemIdstringCross-Entity-Erstellung aus einem Problem

Verknüpfungen zu Tickets und Problems: relatedTickets und relatedProblems verlangen dasselbe Recht wie der Verknüpfungs-Endpunkt (changes.linkToTickets bzw. changes.linkToProblems, sonst 403), außerdem die Sicht auf die jeweilige Gegenseite. Ein Speichern, das die Verknüpfungen unverändert lässt, verlangt das Recht nicht. Sie sind an einen angemeldeten Benutzer gebunden (API-Key: 400 CHANGE_LINKS_REQUIRE_USER), und an einem geschlossenen Change lassen sich keine neuen Verknüpfungen anlegen. Jede Verknüpfung schreibt auf BEIDEN Seiten einen Timeline-Eintrag.

Genehmigungs-Workflow

Genehmigungen laufen über das zentrale Unified-Approval-Framework. Am Change werden Approver nur zugewiesen; die eigentliche Entscheidung erfolgt über die Approvals API.

Schritt 1: Einreichen (DRAFT → SUBMITTED)

POST /api/changes/:id/submit
{
  "changeManagerId": "clx-change-manager-id",
  "notes": "Ready for review"
}

Schritt 2: Approver zuweisen

POST /api/changes/:id/approvers
{
  "userId": "clx-manager-id"
}

Response (201 Created)

{
  "id": "clx-approval-id",
  "userId": "clx-manager-id",
  "required": true,
  "decision": null,
  "decisionAt": null,
  "comment": null,
  "user": { "id": "clx-manager-id", "name": "Jane Manager", "email": "jane@example.com" },
  "sourceGroup": { "id": "clx-cab-group", "name": "cab", "displayName": "Change Advisory Board" },
  "isManual": true,
  "sequence": 0
}
  • Berechtigung changes.addApprover plus die Sicht auf diesen Change (dieselbe Prüfung wie bei Detail und Kommentar).
  • Nur möglich, solange der Change in SUBMITTED oder PENDING_APPROVAL ist (sonst APPROVER_INVALID_STATUS).
  • 4-Augen-Prinzip: Requestor und zugewiesener Change Manager können nicht Approver sein (403 CONFLICT_OF_INTEREST).
  • Der manuell hinzugefügte Approver hängt an der laufenden Genehmigungsrunde — sourceGroup ist entsprechend gefüllt, und seine Entscheidung zählt in deren Auswertung mit.

Schritt 3: Zur Genehmigung routen (SUBMITTED → PENDING_APPROVAL)

POST /api/changes/:id/route-to-approval
{
  "skipApproval": false,
  "notes": "Routing to CAB"
}

Mit skipApproval: true springt der Change direkt auf APPROVED (Berechtigung changes.manageWorkflow).

Schritt 4: Approver entscheiden

POST /api/approvals/:id/decide

Die Entscheidung wird über das zentrale Approval-Framework getroffen. Sobald alle erforderlichen Approver zugestimmt haben, wechselt der Change automatisch auf APPROVED; bei Ablehnung auf REJECTED. Details, Request-/Response-Format und Permission changes.approve siehe Approvals API.

Change-Tasks im Detail

Change-Tasks bilden die konkrete Umsetzung ab. Jeder Task hat einen kind, eine phase, einen Status und ist entweder einer Person oder einer Agent-Gruppe zugewiesen.

Feld Werte Beschreibung
kindIMPLEMENTATION, TEST, ROLLBACKArt des Tasks
phasePREP, EXECUTE, VALIDATE, POSTCHECKPhase (Default: EXECUTE)
statusPENDING, BLOCKED, IN_PROGRESS, DONE, SKIPPED, FAILEDBLOCKED wenn Abhängigkeiten offen sind
assignedToId XOR assignedGroupIdcuidPerson ODER Gruppe – niemals beides
dependsOnTaskIdscuid[]Vorgänger-Tasks (Zyklus-Check serverseitig)
estimatedMinutes / actualMinutesnumberZeit-Tracking
completionNote / skipReason / failureReasonstringPflicht bei complete / skip / fail
handoverNotesstringÜbergabe an abhängige Tasks
versionnumberOptimistic Lock – bei jeder Mutation Pflicht

Task erstellen

POST /api/changes/:changeId/tasks
{
  "kind": "IMPLEMENTATION",
  "phase": "EXECUTE",
  "title": "Run pg_upgrade on primary",
  "description": "Execute pg_upgrade and verify cluster starts",
  "assignedGroupId": "clx-dba-group-id",
  "estimatedMinutes": 45,
  "dependsOnTaskIds": ["clx-prep-task-id"]
}

Task-Lebenszyklus

# Assign user OR group (version required)
POST /api/changes/:changeId/tasks/:taskId/assign
{ "assignedToId": "clx-user-id", "version": 1 }

# Start – on group assignment the starting agent is atomically set as assignedToId
POST /api/changes/:changeId/tasks/:taskId/start
{ "version": 2 }

# Complete (completionNote required)
POST /api/changes/:changeId/tasks/:taskId/complete
{ "completionNote": "pg_upgrade completed, cluster healthy", "actualMinutes": 38, "version": 3 }

# Skip / fail
POST /api/changes/:changeId/tasks/:taskId/skip   { "skipReason": "Not needed, already on v16", "version": 2 }
POST /api/changes/:changeId/tasks/:taskId/fail   { "failureReason": "pg_upgrade aborted: incompatible cluster", "version": 2 }

Berechtigungen: Verwalten (create/update/delete/reorder/assign/skip/bulk/retry) erfordert changes.manageTasks ODER (changes.editOwn als Requestor) ODER Change-Assignee/aktives Gruppenmitglied. Ausführen (start/complete/fail) erfordert changes.manageTasks ODER (changes.executeTask mit Beteiligung). Kommentieren genügt eine der beiden Ebenen. Hinweis: changes.editAll allein gewährt KEINE Task-Rechte.

Die Task-Struktur ist während der Genehmigung eingefroren: Solange ein Change in PENDING_APPROVAL steht, lassen sich weder Tasks anlegen, ändern, löschen noch umsortieren — das Gremium bewertet einen unveränderlichen Vorschlag. Überspringen (skip) ist nur in der gerade aktiven Phase möglich. Ein fehlgeschlagener Task lässt sich über retry wieder aufnehmen.

Kalender-Einladungen (.ics)

Wird ein Change-Task einer Person zugewiesen und der Change hat scheduledStartTime und scheduledEndTime, verschickt Eviworx eine Kalender-Einladung (.ics, METHOD:REQUEST) an die zuständige Person. Bei Neuzuweisung/Storno geht eine CANCEL-Einladung an die vorherige Person.

  • .ics-REQUEST nur, wenn der Change in einem der Status SCHEDULED, APPROVED, IN_PROGRESS ist und Start/Ende gesetzt sind.
  • CANCEL wird unabhängig vom Status verschickt, sobald Schedule-Daten existieren.

Change aktualisieren

PATCH /api/changes/:id

PATCH aktualisiert nur Datenfelder – KEIN status (dafür gibt es Transition-Endpoints). Erfordert changes.editAll ODER changes.editOwn (als Requestor). Eine Änderung von assignedToId/assignedGroupId zusätzlich changes.assign. Das Feld version ist PFLICHT (Optimistic Locking, 409 CHANGE_VERSION_CONFLICT bei veraltetem Stand); null leert ein Feld, ein weggelassener Schlüssel lässt es unverändert. Welche Felder im aktuellen Status editierbar/gesperrt/erforderlich sind, liefert GET /:id/field-permissions — ein gesperrtes Feld zu senden endet mit 400 LOCKED_FIELD_MODIFICATION.

Changes abrufen (Liste)

GET /api/changes?f.status=in:PENDING_APPROVAL,APPROVED&f.type=NORMAL&sort=scheduledStartTime:asc&page=1&per=20

Die Liste ist RBAC-gefiltert (viewAll / viewOwn / viewPendingApprovals) und unterstützt Filter und Sortierung. Ein Filter hat die Form f.<feld>=<operator>:<wert>; ohne Operator-Präfix gilt Gleichheit. Antwort:

{
  "data": [ /* changes */ ],
  "pagination": { "page": 1, "limit": 20, "total": 137, "totalPages": 7, "hasMore": true }
}

Query Parameters

Parameter Beschreibung
f.status, f.type, f.priority, f.riskLevel, f.impactEnum-Filter (eq/neq/in/notIn, Werte in Großschreibung)
f.number, f.titleText-Filter (eq/contains/startsWith)
f.requestorId, f.assignedToId, f.categoryIdZuordnungs-Filter (eq/in, teils isNull/isNotNull)
f.scheduledStartTime, f.scheduledEndTime, f.createdAt, f.updatedAtZeit-Filter (gt/gte/lt/lte/between/relative)
qSuche über Nummer, Titel, Beschreibung
page / per / sortSeitenweise Ausgabe (per Standard 25, maximal 200)
deleted=1Papierkorb: NUR gelöschte Changes (erfordert changes.viewDeleted; akzeptiert ausschließlich den Wert 1)
includeDeleted=trueMischliste inkl. gelöschter (erfordert changes.viewDeleted)
relatedTicketId, relatedProblemIdNach Verlinkung filtern

Fehlerbehandlung

Self-Approval blockiert (4-Augen)

{
  "errorCode": "CONFLICT_OF_INTEREST",
  "message": "Requestor and assigned change manager cannot be an approver of this change."
}

Approver in falschem Status (400)

{
  "errorCode": "APPROVER_INVALID_STATUS",
  "message": "Cannot add an approver while the change is in status SCHEDULED",
  "status": "SCHEDULED"
}

Pflichtfeld fehlt (Transition, 400)

{
  "error": "VALIDATION_ERROR",
  "details": [
    { "field": "resolution", "message": "Resolution notes must be at least 20 characters" }
  ]
}

Code-Beispiel: Kompletter Lifecycle (JavaScript)

// ===================================================
// COMPLETE CHANGE LIFECYCLE
// Status NEVER set via PATCH — always dedicated endpoints.
// ===================================================

const API_URL = 'https://your-instance.com/api';
const headers = { 'Content-Type': 'application/json' };
const post = (path, body) => fetch(`${API_URL}${path}`, {
  method: 'POST', credentials: 'include', headers,
  body: body ? JSON.stringify(body) : undefined,
}).then(r => r.json());

// 1. Create change (UPPER enum values, inline tasks)
const change = await post('/changes', {
  title: 'Upgrade PostgreSQL to version 16',
  description: 'Database upgrade for security and performance reasons',
  justification: 'Security patches for CVE-2024-xxx, performance improvements',
  type: 'NORMAL',
  categoryId: 'clx-category-id',
  priority: 'HIGH',
  riskLevel: 'MEDIUM',
  impact: 'HIGH',
  urgency: 'MEDIUM',
  scheduledStartTime: '2026-02-01T02:00:00Z',
  scheduledEndTime: '2026-02-01T04:00:00Z',
  plannedDuration: 120,
  tasks: [
    { clientKey: 'impl', kind: 'IMPLEMENTATION', title: 'Run pg_upgrade' },
    { kind: 'TEST', title: 'Run integration tests', dependsOnTaskKeys: ['impl'] },
    { kind: 'ROLLBACK', title: 'Restore from backup if needed' },
  ],
});
console.log('Created:', change.number); // CHG-2026-000042

// 2. Submit (DRAFT → SUBMITTED), set change manager
await post(`/changes/${change.id}/submit`, { changeManagerId: 'clx-cm-id' });

// 3. Assign an approver (must not be requestor/change manager)
const approver = await post(`/changes/${change.id}/approvers`, { userId: 'clx-cab-member' });

// 4. Route to approval (SUBMITTED → PENDING_APPROVAL)
await post(`/changes/${change.id}/route-to-approval`, { skipApproval: false });

// 5. Approver decides via the unified approvals framework (different user!)
await post(`/approvals/${approver.id}/decide`, { decision: true, comment: 'Looks good' });
// → all required approvers done ⇒ change auto-transitions to APPROVED

// 6. Schedule (APPROVED → SCHEDULED) — .ics invites go out for assigned tasks
await post(`/changes/${change.id}/schedule`, {
  scheduledStartTime: '2026-02-01T02:00:00Z',
  scheduledEndTime: '2026-02-01T04:00:00Z',
});

// 7. Start implementation (SCHEDULED → IN_PROGRESS)
await post(`/changes/${change.id}/start-implementation`, { notes: 'Window opened' });

// 8. Work the tasks (start → complete, version-locked)
const tasks = await fetch(`${API_URL}/changes/${change.id}/tasks`, { credentials: 'include' }).then(r => r.json());
for (const t of tasks) {
  await post(`/changes/${change.id}/tasks/${t.id}/start`, { version: t.version });
  await post(`/changes/${change.id}/tasks/${t.id}/complete`, {
    completionNote: 'Done and verified', version: t.version + 1,
  });
}

// 9. Complete the change (IN_PROGRESS → COMPLETED)
await post(`/changes/${change.id}/complete`, {
  resolution: 'Upgrade completed successfully, all tests green',
  closerId: 'clx-cm-id',
});

// 10. Close (COMPLETED → CLOSED)
await post(`/changes/${change.id}/close`, {
  reviewNotes: 'Post-implementation review passed, no incidents',
  successCriteriaMet: true,
});

Rollback-Szenario

Wenn die Umsetzung schiefgeht, gibt es zwei Wege:

# A) Controlled rollback: IN_PROGRESS → ROLLING_BACK → BACKED_OUT
POST /api/changes/:id/initiate-rollback
{ "reason": "Integration tests failed, queries timing out — rolling back to v15" }

POST /api/changes/:id/backout
{ "resolution": "Restored from backup, cluster back on v15 and healthy", "closerId": "clx-cm-id" }

# B) Failure without rollback: IN_PROGRESS → FAILED
POST /api/changes/:id/fail
{ "resolution": "pg_upgrade aborted: incompatible cluster versions", "closerId": "clx-cm-id", "backoutPerformed": false }

# Then close: FAILED/BACKED_OUT → CLOSED
POST /api/changes/:id/close
{ "reviewNotes": "Root cause documented, retry planned for next window" }
Kernprinzipien
  • ✓ Status nur über Transition-Endpoints
  • ✓ Genehmigung über Unified-Approval-Framework
  • ✓ 4-Augen-Prinzip erzwungen
  • ✓ Strukturierte Change-Tasks mit Optimistic Lock
  • ✓ Kalender-Einladungen (.ics) für geplante Arbeit
🔐
Berechtigungen (RBAC)
  • changes.viewAll / viewOwn / viewPendingApprovals
  • changes.create / editAll / editOwn
  • changes.assign / addApprover
  • changes.submit / manageWorkflow / schedule
  • changes.startImplementation / markCompleted / markFailed
  • changes.backout / close / returnToDraft
  • changes.manageTasks / executeTask
  • changes.delete / restore
  • changes.viewTemplates / viewDraftTemplates / createTemplates
  • changes.editOwnTemplates / editAllTemplates / submitTemplates / retireTemplates / deleteTemplates

Auth-/Rollenmodell: Permissions & RBAC

Nächster Schritt

Problems API → Erfahre mehr über die Problems API
Entity Linking API → Changes mit Tickets/Problems/Incidents/Assets verknüpfen