Appearance
The Three Demo Workflows
These are the complete, working definitions behind the demo's Self-service portal. Paste each into the workflow editor's JSON tab (or POST /api/v1/workflows) and adapt org/repo/project ids to your own.
1. Deploy Stack (GitHub Actions)
A rolling deployment: three GitHub repositories deployed in sequence (orders → payments → frontend), then the result recorded as a deployment entity — the recording step runs ALWAYS, so failures are recorded too.
json
{
"identifier": "deploy-stack-github",
"title": "Deploy Stack (GitHub Actions)",
"icon": "LucideGithub",
"description": "Rolling deployment of the order stack: orders-service, then payments-service, then frontend-webapp — each via GitHub Actions in its own repository. Records a deployment entity.",
"kind": "WORKFLOW",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"required": ["environment", "version"],
"properties": {
"version": { "type": "string", "title": "Version", "default": "1.0.0" },
"environment": {
"enum": ["dev", "staging", "prod"],
"type": "string",
"title": "Environment",
"default": "staging"
}
}
},
"blueprintIdentifier": "deployment"
},
"published": true,
"steps": [
{
"identifier": "deploy_orders",
"title": "Deploy orders-service (GitHub)",
"order": 0,
"type": "GITHUB",
"config": {
"org": "idpnextdemo",
"ref": "main",
"repo": "orders-service",
"workflow": "deploy.yml",
"workflowInputs": {
"version": "{{ .inputs.version }}",
"environment": "{{ .inputs.environment }}"
}
},
"dependsOn": [],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "deploy_payments",
"title": "Deploy payments-service (GitHub)",
"order": 1,
"type": "GITHUB",
"config": {
"org": "idpnextdemo",
"ref": "main",
"repo": "payments-service",
"workflow": "deploy.yml",
"workflowInputs": {
"version": "{{ .inputs.version }}",
"environment": "{{ .inputs.environment }}"
}
},
"dependsOn": ["deploy_orders"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "deploy_frontend",
"title": "Deploy frontend-webapp (GitHub)",
"order": 2,
"type": "GITHUB",
"config": {
"org": "idpnextdemo",
"ref": "main",
"repo": "frontend-webapp",
"workflow": "deploy.yml",
"workflowInputs": {
"version": "{{ .inputs.version }}",
"environment": "{{ .inputs.environment }}"
}
},
"dependsOn": ["deploy_orders", "deploy_payments"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "record",
"title": "Record deployment",
"order": 3,
"type": "UPSERT_ENTITY",
"config": {
"mapping": {
"title": "Deploy {{ .inputs.version }} to {{ .inputs.environment }} (GitHub)",
"identifier": "{{ .run.id }}",
"properties": {
"url": "https://idpnext.wazyneo.com/self-service/runs/{{ .run.id }}",
"status": "{{ .steps.deploy_frontend.status }}",
"version": "{{ .inputs.version }}",
"provider": "github",
"services": ["orders-service", "payments-service", "frontend-webapp"],
"workflow": "Deploy Stack (GitHub Actions)",
"environment": "{{ .inputs.environment }}",
"triggeredBy": "{{ .user.email }}"
}
},
"blueprintIdentifier": "deployment"
},
"dependsOn": ["deploy_frontend"],
"condition": "ALWAYS",
"timeoutMinutes": 10
}
]
}Points to notice:
- Each
GITHUBstep targets thedeploy.ymlfrom Part 3 and forwards the two user inputs. The IDP addsport_run_idautomatically. recorddepends on the last deploy but has"condition": "ALWAYS"— the Deployments page shows failed deployments too, withstatustaken from{{ .steps.deploy_frontend.status }}.
2. Deploy Stack (GitLab CI)
Same idea with GitLab: analytics first, then orders and payments in parallel (both depend only on deploy_analytics). The recorded status is computed with a jq conditional over both parallel steps.
json
{
"identifier": "deploy-stack-gitlab",
"title": "Deploy Stack (GitLab CI)",
"icon": "LucideGitBranch",
"description": "Deploys analytics-pipeline first, then orders-service and payments-service in parallel — each via a GitLab CI pipeline in its own project. Records a deployment entity.",
"kind": "WORKFLOW",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"required": ["environment", "version"],
"properties": {
"version": { "type": "string", "title": "Version", "default": "1.0.0" },
"environment": {
"enum": ["dev", "staging", "prod"],
"type": "string",
"title": "Environment",
"default": "staging"
}
}
},
"blueprintIdentifier": "deployment"
},
"published": true,
"steps": [
{
"identifier": "deploy_analytics",
"title": "Deploy analytics-pipeline (GitLab)",
"order": 0,
"type": "GITLAB",
"config": {
"ref": "main",
"projectId": 84432928,
"pipelineVariables": {
"DEPLOY_ENV": "{{ .inputs.environment }}",
"DEPLOY_VERSION": "{{ .inputs.version }}"
}
},
"dependsOn": [],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "deploy_orders",
"title": "Deploy orders-service (GitLab)",
"order": 1,
"type": "GITLAB",
"config": {
"ref": "main",
"projectId": 84432919,
"pipelineVariables": {
"DEPLOY_ENV": "{{ .inputs.environment }}",
"DEPLOY_VERSION": "{{ .inputs.version }}"
}
},
"dependsOn": ["deploy_analytics"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "deploy_payments",
"title": "Deploy payments-service (GitLab)",
"order": 2,
"type": "GITLAB",
"config": {
"ref": "main",
"projectId": 84432915,
"pipelineVariables": {
"DEPLOY_ENV": "{{ .inputs.environment }}",
"DEPLOY_VERSION": "{{ .inputs.version }}"
}
},
"dependsOn": ["deploy_analytics"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "record",
"title": "Record deployment",
"order": 3,
"type": "UPSERT_ENTITY",
"config": {
"mapping": {
"title": "Deploy {{ .inputs.version }} to {{ .inputs.environment }} (GitLab)",
"identifier": "{{ .run.id }}",
"properties": {
"url": "https://idpnext.wazyneo.com/self-service/runs/{{ .run.id }}",
"status": "{{ if (.steps.deploy_orders.status == \"SUCCESS\") and (.steps.deploy_payments.status == \"SUCCESS\") then \"SUCCESS\" else \"FAILURE\" end }}",
"version": "{{ .inputs.version }}",
"provider": "gitlab",
"services": ["analytics-pipeline", "orders-service", "payments-service"],
"workflow": "Deploy Stack (GitLab CI)",
"environment": "{{ .inputs.environment }}",
"triggeredBy": "{{ .user.email }}"
}
},
"blueprintIdentifier": "deployment"
},
"dependsOn": ["deploy_orders", "deploy_payments"],
"condition": "ALWAYS",
"timeoutMinutes": 10
}
]
}projectId is the numeric GitLab project id (Project → Settings → General, or GET /api/v4/groups/<group>/projects).
3. Full-Stack Release (GitHub + GitLab)
The governance showcase: an approval gate, then a GitHub deployment, then a GitLab deployment, then recording. The GitHub step authenticates with a stored secret instead of the server environment.
json
{
"identifier": "release-full-stack",
"title": "Full-Stack Release (GitHub + GitLab)",
"icon": "LucideRocket",
"description": "Approval-gated release: deploys the backend via GitHub Actions (orders-service), then the frontend via a GitLab CI pipeline (frontend-webapp). Records a deployment entity.",
"kind": "WORKFLOW",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"required": ["environment", "version"],
"properties": {
"version": { "type": "string", "title": "Version", "default": "1.0.0" },
"environment": {
"enum": ["dev", "staging", "prod"],
"type": "string",
"title": "Environment",
"default": "prod"
}
}
},
"blueprintIdentifier": "deployment"
},
"published": true,
"steps": [
{
"identifier": "approve",
"title": "Release approval",
"order": 0,
"type": "APPROVAL",
"config": {
"approvers": [],
"onTimeout": "approve",
"timeoutMinutes": 5
},
"dependsOn": [],
"condition": "ON_SUCCESS",
"timeoutMinutes": 5
},
{
"identifier": "deploy_backend",
"title": "Deploy orders-service backend (GitHub)",
"order": 1,
"type": "GITHUB",
"config": {
"org": "idpnextdemo",
"ref": "main",
"repo": "orders-service",
"workflow": "deploy.yml",
"credentials": {
"source": "secret",
"version": "latest",
"secretIdentifier": "idpnetxdemo-github-app"
},
"workflowInputs": {
"version": "{{ .inputs.version }}",
"environment": "{{ .inputs.environment }}"
}
},
"dependsOn": ["approve"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "deploy_frontend",
"title": "Deploy frontend-webapp (GitLab)",
"order": 2,
"type": "GITLAB",
"config": {
"ref": "main",
"projectId": 84432930,
"pipelineVariables": {
"DEPLOY_ENV": "{{ .inputs.environment }}",
"DEPLOY_VERSION": "{{ .inputs.version }}"
}
},
"dependsOn": ["deploy_backend"],
"condition": "ON_SUCCESS",
"timeoutMinutes": 10
},
{
"identifier": "record",
"title": "Record deployment",
"order": 3,
"type": "UPSERT_ENTITY",
"config": {
"mapping": {
"title": "Release {{ .inputs.version }} to {{ .inputs.environment }} (Full stack)",
"identifier": "{{ .run.id }}",
"properties": {
"url": "https://idpnext.wazyneo.com/self-service/runs/{{ .run.id }}",
"status": "{{ .steps.deploy_frontend.status }}",
"version": "{{ .inputs.version }}",
"provider": "mixed",
"services": ["orders-service", "frontend-webapp"],
"workflow": "Full-Stack Release (GitHub + GitLab)",
"environment": "{{ .inputs.environment }}",
"triggeredBy": "{{ .user.email }}"
}
},
"blueprintIdentifier": "deployment"
},
"dependsOn": ["deploy_frontend"],
"condition": "ALWAYS",
"timeoutMinutes": 10
}
]
}The APPROVAL step config:
approvers: []— any user who can see the run may approve or decline. List user emails to restrict it.onTimeout: "approve"+timeoutMinutes: 5— if nobody decides within 5 minutes, the release auto-approves (demo-friendly; in production you'd typically use"reject").
Approvals need a human
Service accounts cannot approve APPROVAL steps ("Failed to record approval decision") — approvals must come from a real user, or from the onTimeout policy.
