PowerDecision User Guide
Decision Wizard
Overview
The Decision Wizard is a visual rule editor that allows business users to create decision models without writing code. It provides a step-by-step interface for defining inputs, outputs, rules, and conditions that are automatically converted to DMN format for execution.
Access: The Decision Wizard is available at /decision-wizard/wizard.html relative to the project root, or via the "Back to Wizard" link in the documentation header.
Wizard Workflow
The wizard guides you through a structured process to create decision models:
| Step | Section | What You Define |
|---|---|---|
| 1 | Model Info | Model ID (unique identifier), name, description, and version |
| 2 | Inputs | Input variables with name, data type (string, number, boolean, date), and optional allowed values |
| 3 | Outputs | Output variables with name, data type, and optional allowed values |
| 4 | Hit Policy | How rules are matched: FIRST, UNIQUE, PRIORITY, ANY, or COLLECT |
| 5 | Rules | Individual rules with conditions on inputs, output values, and optional priority/reason |
| 6 | Review | Preview the complete decision model and submit to the API |
Features
- Template loading — Start from any of the 7 pre-built templates (loan approval, credit limit, etc.)
- Condition builder — Visual dropdowns for operators (equals, greater than, between, in list, etc.)
- Multi-output support — Define multiple output columns per rule
- Default rules — Add a catch-all rule that matches when no other rules do
- JSON export — Download the model definition as JSON for version control
- Direct upload — Submit the model directly to the PowerDecision API for immediate use
- Validation — Real-time validation of inputs, outputs, and rule completeness
Hit Policy Auto-Correction: If you select UNIQUE hit policy but include a default rule (a rule with no conditions), the engine automatically switches to FIRST policy since UNIQUE requires exactly one match per input combination.
API Reference
All API endpoints are served on port 8031 by default. The base path for decision endpoints is /api/powerdecision/v1.
Submit Decision
Submit a decision request for asynchronous evaluation. Returns a job ID for polling.
| Property | Value |
|---|---|
| Method | POST |
| Endpoint | /api/powerdecision/v1/decisions |
| Content-Type | application/json |
Request Body (DecisionSpec):
{
"model_id": "loan_approval",
"version": "1.0",
"context": {
"purpose": "Evaluate loan application"
},
"inputs": {
"credit_score": 720,
"annual_income": 85000,
"loan_amount": 250000,
"employment_status": "employed",
"debt_to_income": 0.28,
"loan_purpose": "home_purchase"
}
}
Request Fields:
| Field | Type | Required | Description |
|---|---|---|---|
model_id | string | Yes | Identifier of the decision model to evaluate |
version | string | No | Model version (defaults to latest) |
context | object | No | Metadata about the decision context |
inputs | object | Yes | Key-value pairs matching the model's input schema |
Response (202 Accepted):
{
"jobId": "dec-a1b2c3d4",
"status": "PENDING"
}
Error Response (400 Bad Request):
{
"error": "Model not found: unknown_model"
}
Get Decision Result
Poll for the result of a submitted decision job.
| Property | Value |
|---|---|
| Method | GET |
| Endpoint | /api/powerdecision/v1/decisions/{jobId} |
Response (200 OK — completed):
{
"model_id": "loan_approval",
"version": "1.0",
"status": "SUCCESS",
"decision": {
"approval_status": "approved",
"max_loan_amount": 300000,
"interest_rate": 4.5,
"reason": "Good credit score with stable employment"
},
"explanation": "Rule 2 matched: credit_score >= 700 AND employment_status = employed",
"metadata": {
"evaluation_time_ms": 45,
"hit_policy": "FIRST",
"rules_evaluated": 5,
"rules_matched": 1
}
}
Response Fields:
| Field | Description |
|---|---|
model_id | The model that was evaluated |
version | Model version used |
status | PENDING, PROCESSING, SUCCESS, or ERROR |
decision | Output values from the decision table (only when SUCCESS) |
explanation | Human-readable explanation of which rules matched |
metadata | Evaluation statistics (time, rules evaluated, etc.) |
Upload Model
Upload a decision model from wizard JSON. The JSON is validated, converted to DMN XML, and stored for evaluation.
| Property | Value |
|---|---|
| Method | POST |
| Endpoint | /api/powerdecision/v1/models/upload |
| Content-Type | application/json |
Request Body:
{
"model_id": "customer_risk",
"name": "Customer Risk Assessment",
"description": "Evaluates customer risk level based on profile data",
"version": "1.0",
"inputs_schema": [
{ "name": "account_age_months", "type": "number" },
{ "name": "transaction_count", "type": "number" },
{ "name": "country", "type": "string" }
],
"outputs_schema": [
{ "name": "risk_level", "type": "string", "allowed_values": ["low", "medium", "high"] },
{ "name": "review_required", "type": "boolean" }
],
"policy": "FIRST",
"rules": [
{
"conditions": [
{ "input": "account_age_months", "operator": "lt", "value": 3 },
{ "input": "country", "operator": "in", "value": ["NG", "PH", "RO"] }
],
"outputs": { "risk_level": "high", "review_required": true },
"priority": 1,
"reason": "New account from high-risk country"
}
]
}
Response (200 OK):
{
"model_id": "customer_risk",
"version": "1.0",
"status": "uploaded",
"message": "Model uploaded and DMN generated successfully"
}
List Models
Returns all registered decision models (both built-in and uploaded).
| Property | Value |
|---|---|
| Method | GET |
| Endpoint | /api/powerdecision/v1/models |
Response (200 OK):
{
"models": [
{
"model_id": "capacity_adjustment",
"name": "Capacity Adjustment",
"version": "1.0",
"type": "builtin",
"description": "Built-in capacity adjustment model"
},
{
"model_id": "loan_approval",
"name": "Loan Approval",
"version": "1.0",
"type": "runtime",
"description": "Uploaded via wizard"
}
],
"count": 2
}
Health Endpoints
PowerDecision provides multiple health check endpoints for different orchestration needs:
| Endpoint | Type | Description |
|---|---|---|
GET /q/health | Quarkus SmallRye | Full health check (liveness + readiness) with Quarkus standard format |
GET /health/liveness | Custom | Lightweight liveness probe — returns {"status": "UP"} |
GET /health/readiness | Custom | Readiness probe — returns {"status": "UP"} |
GET /q/health/live | Quarkus SmallRye | Quarkus-native liveness check |
GET /q/health/ready | Quarkus SmallRye | Quarkus-native readiness check |
Orchestrator Integration: PowerOrchestrator uses the custom /health/liveness endpoint for health monitoring. The /q/health endpoints follow the Quarkus SmallRye Health standard and include additional subsystem checks.
Additional Development Endpoints:
| Endpoint | Description |
|---|---|
GET /openapi | OpenAPI 3.0 specification (JSON) |
GET /swagger-ui.html | Interactive Swagger UI for API exploration |
GET /q/health-ui | Quarkus Health UI dashboard |
Model Management
Built-in Models
PowerDecision ships with pre-compiled DMN models that are available immediately without upload:
| Model ID | Description | Type |
|---|---|---|
capacity_adjustment | Capacity adjustment decision for the PDP pipeline | Built-in (Kogito-compiled) |
Built-in models are compiled into the application at build time via Kogito. They are evaluated through the Kogito runtime directly, which provides the fastest execution path.
Uploading Models
Models uploaded via the wizard or API go through this pipeline:
- Validation — The model_id is checked for uniqueness and format
- DMN Generation —
DmnGeneratorconverts the JSON to DMN XML with FEEL expressions - File Storage — The DMN XML is written to
models/{model_id}.dmn - Registry Update — Model metadata is stored in Redis for quick lookup
- Runtime Ready — The model is immediately available for evaluation via
RuntimeDmnEvaluator
Runtime vs Built-in: Uploaded models use RuntimeDmnEvaluator (KIE container per evaluation), which is slightly slower than Kogito-compiled built-in models. For production-critical models, consider compiling them as Kogito resources.
Model Registry
The model registry uses Redis as the metadata store with filesystem as the source of truth for DMN files:
- Redis — Stores model metadata (ID, name, version, type, timestamps)
- Filesystem — Stores the actual DMN XML files in the
models/directory - Startup sync — On startup, the registry loads from Redis and scans the filesystem for orphaned DMN files not yet registered
- Fallback — If Redis is unavailable, models are still loaded from the filesystem
Configuration
Environment Variables
PowerDecision is configured via Quarkus application properties and environment variables:
| Variable | Default | Description |
|---|---|---|
QUARKUS_HTTP_PORT | 8031 | HTTP server port |
QUARKUS_HTTP_CORS | true | Enable CORS |
QUARKUS_HTTP_CORS_ORIGINS | * | Allowed CORS origins |
QUARKUS_REDIS_HOSTS | redis://localhost:6379 | Redis connection URL |
MODELS_PATH | models | Directory for DMN model files |
JAVA_OPTS | none | JVM options (e.g., -Xmx512m) |
QUARKUS_LOG_LEVEL | INFO | Application log level |
QUARKUS_SMALLRYE_HEALTH_UI_ALWAYS_INCLUDE | true | Enable health UI |
QUARKUS_SWAGGER_UI_ALWAYS_INCLUDE | true | Enable Swagger UI in production |
CORS Configuration
CORS is enabled by default with permissive settings for development. For production, restrict origins:
# application.properties
quarkus.http.cors=true
quarkus.http.cors.origins=https://yourdomain.com,https://wizard.yourdomain.com
quarkus.http.cors.methods=GET,POST,PUT,DELETE,OPTIONS
quarkus.http.cors.headers=Content-Type,Authorization
Production: Replace the wildcard * origin with specific domains in production to prevent unauthorized cross-origin access.
Redis Configuration
Redis is used for the model registry metadata. If Redis is unavailable, the system falls back to filesystem-only mode.
# Default Redis configuration
quarkus.redis.hosts=redis://localhost:6379
# Docker Compose maps container port 6379 to host port 6381
# to avoid conflicts with other Redis instances
quarkus.redis.hosts=redis://redis:6379 # inside Docker network
Redis stores:
- Model metadata (JSON hash per model_id)
- Model version history
- Registry index for fast model listing
Deployment
Docker
PowerDecision uses a multi-stage Docker build (Maven build → JRE 17 Alpine runtime):
# Build the image
docker build -t powerdecision-api ./decision-api
# Run standalone
docker run -d \
--name powerdecision \
-p 8031:8031 \
-v $(pwd)/models:/app/models \
-e QUARKUS_REDIS_HOSTS=redis://host.docker.internal:6379 \
powerdecision-api
The Dockerfile uses a custom entrypoint that starts the Quarkus application with the -Dquarkus.http.host=0.0.0.0 flag to listen on all interfaces.
Docker Compose
The recommended way to run PowerDecision with its Redis dependency:
# Start all services
docker compose up -d
# View logs
docker compose logs -f decision-api
# Stop all services
docker compose down
The Docker Compose configuration includes:
| Service | Image | Port | Description |
|---|---|---|---|
decision-api | Built from Dockerfile | 8031:8031 | PowerDecision API server |
redis | redis:7-alpine | 6381:6379 | Model registry store |
Persistent volumes:
./models:/app/models— DMN model files (filesystem storage)redis-data:/data— Redis persistence
Hetzner Cloud Deployment
For production deployment on Hetzner Cloud, refer to the Hetzner Deployment Guide in the project root. Key considerations for PowerDecision:
- Memory — JVM-based application; allocate at least 512 MB for the container
- Redis — Can share a Redis instance with other PowerTools products, but use a different database number
- Models volume — Mount a persistent volume for the
models/directory to survive container restarts - Health checks — Use
/health/livenessfor Docker HEALTHCHECK and orchestrator monitoring - Reverse proxy — Expose through Traefik or nginx with TLS termination
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| Model not found error | Model ID doesn't exist in registry | Check GET /models for available models. Upload the model first via wizard or API. |
| DMN generation fails | Invalid wizard JSON schema | Ensure inputs_schema, outputs_schema, and rules follow the expected format. Check that all condition operators are valid. |
| UNIQUE policy auto-corrected | Default rule present with UNIQUE policy | This is expected behavior. UNIQUE requires exactly one match; default rules always match. Engine switches to FIRST automatically. |
| Job stuck in PROCESSING | DMN evaluation error or timeout | Check application logs. Verify input types match the model's input schema. Ensure FEEL expressions are valid. |
| Redis connection refused | Redis not running or wrong port | Verify Redis is running. Check QUARKUS_REDIS_HOSTS. Docker Compose maps port 6381→6379. |
| Model not available after restart | Redis data lost, no filesystem backup | Ensure Redis persistence is enabled or models are stored on a persistent volume. On startup, the registry scans the filesystem for orphaned DMN files. |
| CORS errors from wizard | Origins not configured | Set QUARKUS_HTTP_CORS_ORIGINS to include the wizard's origin. Default is * (all origins). |
| Swagger UI not loading | Disabled in production mode | Set quarkus.swagger-ui.always-include=true in application.properties or environment. |
| OutOfMemoryError | JVM heap too small for many models | Increase heap with JAVA_OPTS=-Xmx1g. Each RuntimeDmnEvaluator creates a KIE container. |
| Evaluation returns empty decision | No rules matched the inputs | Add a default rule (no conditions) as a catch-all. Check that FEEL expressions match your input values. |