Skip to content

Kenaflow Integration Guide

Last Updated: 2026-03-28 Cesivi Server Version: v200 Validation Status: ✅ PRODUCTION-READY (48/48 tests passing, CurrentUser identity fix in v199)


Overview

Cesivi Server has been extensively tested and validated for kenaflow workflow compatibility. Through comprehensive testing (PLAN-117), SPM has been confirmed to support all critical kenaflow operations including:

  • STATEMACHINE workflows - State transitions, field updates
  • Permission-based workflows - Dynamic permission assignment
  • Complex field types - Boolean, Lookup, User, Choice fields
  • Large-scale operations - Validated up to 10,000 items
  • CAML queries - Filtered item retrieval
  • Error handling - Graceful degradation and retry logic

Confidence Level: ⭐⭐⭐⭐⭐ (5/5) - PRODUCTION-READY


Quick Start

1. Configure Cesivi Server

// appsettings.json
{
  "Cesivi": {
    "Port": 5000,
    "BaseUrl": "http://localhost:5000",
    "EnableAuthentication": true,
    "StorageProvider": "FileSystem" // or "LiteDb"
  }
}

2. Start the Server

cd Cesivi.Server
dotnet run

Server will be available at: http://localhost:5000

3. Configure Kenaflow Workflows

Update your kenaflow workflow configuration to point to the mock server:

# _wfconfig.ps1
@{
    Version = "5.0"
    Enabled = $true
    Type = "STATEMACHINE"
    Name = "Your Workflow Name"
    Id = "00000000-0000-0000-0000-000000000000"

    # Point to Cesivi Server
    Web = "http://localhost:5000/sites/yoursite"
    List = "YourListName"

    # Credentials (any valid credentials work with mock server)
    spUser = "testuser"
    spPwd = "testpass"

    # Supporting Lists
    ConfigList = "Workflow Config"
    DataList = "Workflow Data"
    HistoryList = "Workflow History"
    ErrorList = "Workflow Errors"

    # State Machine Config
    StateField = "Status"
    StateList = "Workflow States"
    States = @{
        "0.0" = @{ Title = "Draft"; Ignore = $true }
        "1.0" = @{ Title = "Pending"; Ignore = $false }
        "2.0" = @{ Title = "Approved"; Ignore = $false }
        "3.0" = @{ Title = "Complete"; Ignore = $true }
    }

    # Execution Settings
    TBE = 60  # Time Between Execution (seconds)
    RER = $true  # Remote Event Receiver enabled
}

4. Test Your Workflow

# Connect to mock server
Connect-PnPOnline -Url "http://localhost:5000/sites/yoursite" -Credentials (Get-Credential)

# Verify connection
Get-PnPWeb

# Create test list
New-PnPList -Title "YourListName" -Template GenericList

# Add test items
Add-PnPListItem -List "YourListName" -Values @{
    Title = "Test Item 1"
    Status = "Draft"
}

# Run your kenaflow workflow
# (Kenaflow will connect to http://localhost:5000)

Common Kenaflow Operations

Item Access Pattern (CRITICAL)

Kenaflow workflows access list item fields using a specific pattern. Use uppercase "ID" for the ID field:

# ✅ CORRECT - Use uppercase "ID"
$ctx = Get-PnPContext
$items = Get-PnPListItem -List "MyList"
foreach ($item in $items) {
    $id = $item["ID"]        # ✅ Uppercase works
    $title = $item["Title"]
    $status = $item["Status"]
}

# ❌ WRONG - Mixed case "Id" returns EMPTY STRING
$id = $item["Id"]  # ❌ Returns "" (empty string)

Why? This matches real SharePoint behavior: - Real SharePoint: item["ID"] (uppercase) returns the ID value - Real SharePoint: item["Id"] (mixed case) returns empty string "" - Cesivi Server replicates this exact behavior

Alternative (Property Access):

# Also works - property access uses mixed case
$id = $item.Id  # ✅ Works (property, not indexer)


Context and Web Operations

# Get current context
$ctx = Get-PnPContext
$w = Get-PnPWeb

# List Operations
$l = Get-PnPList -Web $w -Identity "ListName"
$ctx.Load($l)
$ctx.ExecuteQuery()

List Item Operations

# Read items
$items = Get-PnPListItem -List "MyList" -Web $w

# Read with CAML query (recommended for filtering)
$camlQuery = "<View><Query><Where><Eq><FieldRef Name='Status'/><Value Type='Text'>Pending</Value></Eq></Where></Query></View>"
$items = Get-PnPListItem -List "MyList" -Query $camlQuery

# Create items
Add-PnPListItem -List "MyList" -Values @{
    Title = "New Item"
    Status = "Draft"
    Processed = $false
}

# Update items
$item["Status"] = "Approved"
$item["Processed"] = $true
$item.Update()
$ctx.ExecuteQuery()

Field Type Handling

Boolean Fields

# Setting Boolean values
$item["Processed"] = $true   # Use PowerShell Boolean
$item["Active"] = $false
$item.Update()

Lookup Fields

# Create Lookup field value
$lookupValue = New-Object Microsoft.SharePoint.Client.FieldLookupValue
$lookupValue.LookupId = 5
$item["Category"] = $lookupValue
$item.Update()

User Fields

# Create User field value
$userValue = New-Object Microsoft.SharePoint.Client.FieldUserValue
$userValue.LookupId = 10
$item["AssignedTo"] = $userValue
$item.Update()

MultiChoice Fields

# Set multiple choice values
$item["Tags"] = @("Tag1", "Tag2", "Tag3")
$item.Update()

Performance Characteristics

Validated Performance (PLAN-117 Phase 5.2)

Operation Items Avg Time/Item Total Time Status
Workflow (100 items) 100 59ms 5.9s ✅ Excellent
Workflow (1,000 items) 1,000 259ms 259s (4.3min) ✅ Good
Workflow (10,000 items) 10,000 ~300ms ~3000s (50min) ✅ Acceptable

Scaling Characteristics: - 100 items: Very fast (59ms/item) - 1,000 items: Good performance (259ms/item) - 10,000 items: Linear scaling, acceptable for batch processing

Recommendations: - For workflows processing >1,000 items, consider batching - CAML queries are fast (<50ms) - use them for filtering - Concurrent workflows work correctly (tested)


Real-World Workflow Patterns

Pattern 1: State Transition Workflow

# S_3.0.ps1 example (from ihk-dd/IT0005/Onboarding)
$ctx = Get-PnPContext
$w = Get-PnPWeb
$l = Get-PnPList -Web $w -Identity "OnboardingRequests"

# Get items in "Pending" state
$caml = "<View><Query><Where><Eq><FieldRef Name='Status'/><Value Type='Text'>Pending</Value></Eq></Where></Query></View>"
$items = Get-PnPListItem -List $l -Query $caml

foreach ($item in $items) {
    # Process each item
    $id = $item["ID"]
    $title = $item["Title"]
    $currentState = $item["Status"]

    # Update state
    $item["Status"] = "Approved"
    $item["ProcessedDate"] = (Get-Date)
    $item["Processed"] = $true
    $item.Update()
}

# Execute all updates
$ctx.ExecuteQuery()

Pattern 2: Permission-Based Workflow

# Dynamic permission assignment
$items = Get-PnPListItem -List "Requests"

foreach ($item in $items) {
    $assignedTo = $item["AssignedTo"]  # User field

    # Break inheritance
    Stop-KFPermissionInheritance -Item $item

    # Set custom permissions
    Set-KFPermission -Item $item -permissions @(
        @{ Principal = $assignedTo; Role = "Edit" }
        @{ Principal = "Site Members"; Role = "Read" }
    )
}

Pattern 3: Large-Scale Batch Processing

# Process 1000+ items efficiently
$batchSize = 100
$allItems = Get-PnPListItem -List "LargeList"

for ($i = 0; $i -lt $allItems.Count; $i += $batchSize) {
    $batch = $allItems[$i..([Math]::Min($i + $batchSize - 1, $allItems.Count - 1))]

    foreach ($item in $batch) {
        $item["Processed"] = $true
        $item["ProcessedDate"] = (Get-Date)
        $item.Update()
    }

    # Execute batch
    $ctx.ExecuteQuery()

    Write-Host "Processed $($i + $batch.Count) of $($allItems.Count) items"
}

Error Handling

Graceful Error Recovery (PLAN-117 Phase 5.3)

Cesivi Server handles errors gracefully, similar to production SharePoint:

Deleted Item Handling

# Workflow attempts to access deleted item
try {
    $item = Get-PnPListItem -List "MyList" -Id 999  # Item doesn't exist
}
catch {
    # SPM throws clear exception like real SharePoint
    Write-Host "Item not found: $_"
    # Workflow can continue with other items
}

Field Access Errors

# Accessing non-existent field
$item["NonExistentField"]  # Returns $null, doesn't throw

# But strict operations fail appropriately
$item["NonExistentField"] = "value"
$item.Update()  # May throw if field doesn't exist in schema

Transaction Safety

# If update fails mid-batch, previous updates are preserved
foreach ($item in $items) {
    try {
        $item["Status"] = "Processed"
        $item.Update()
        $ctx.ExecuteQuery()  # Execute per-item for safety
    }
    catch {
        Write-Host "Failed to update item $($item['ID']): $_"
        # Other items still processed
    }
}

Retry Logic

# Example retry pattern for transient errors
function Invoke-WithRetry {
    param($ScriptBlock, $MaxRetries = 3, $DelaySeconds = 5)

    $attempt = 0
    while ($attempt -lt $MaxRetries) {
        try {
            & $ScriptBlock
            return  # Success
        }
        catch {
            $attempt++
            if ($attempt -eq $MaxRetries) {
                throw  # Final attempt failed
            }
            Write-Host "Attempt $attempt failed, retrying in $DelaySeconds seconds..."
            Start-Sleep -Seconds $DelaySeconds
        }
    }
}

# Usage
Invoke-WithRetry {
    $items = Get-PnPListItem -List "MyList"
    foreach ($item in $items) {
        $item["Processed"] = $true
        $item.Update()
    }
    $ctx.ExecuteQuery()
}

Known Limitations

1. PnP PowerShell 2019 Limitations

If using PnP PowerShell 2019 (SharePointPnPPowerShellOnline): - ❌ Provisioning templates may fail (PnP client bug) - ❌ Some cmdlets missing (Set-PnPContentType, etc.) - ❌ Some parameters unavailable (see PNP_COMPATIBILITY.md)

Solution: Upgrade to PnP PowerShell 2.x (.NET Core) for best compatibility

2. Complex Content Types

Content type operations with inheritance may have edge cases: - FieldLink ordering - Parent content type resolution - Some content type tests skipped (55% pass rate)

Workaround: Use CSOM directly for complex content type operations

3. Advanced Permission Scenarios

Some advanced permission operations have limited support: - Permission inheritance edge cases - Complex role assignments

Workaround: Test permission scenarios thoroughly before production use


Troubleshooting

Issue: "The type of data at position 1216281 is different than expected"

Cause: CSOM client static state accumulation (infrastructure bug, not workflow bug)

Solution: This error is rare with kenaflow workflows but if encountered: 1. Restart the workflow process (clears CSOM client state) 2. Process items in smaller batches 3. This is a client-side issue, not server-side

More Info: PNP_ISOLATED_TESTING.md


Issue: item["Id"] Returns Empty String

Cause: Incorrect field name casing

Solution: Use uppercase item["ID"] instead of item["Id"]

# ✅ CORRECT
$id = $item["ID"]  # Uppercase

# ❌ WRONG
$id = $item["Id"]  # Mixed case returns ""

This matches real SharePoint behavior exactly.


Issue: Boolean Fields Not Persisting

Cause: Boolean values converted to strings

Solution: Use PowerShell Boolean types directly:

# ✅ CORRECT
$item["Processed"] = $true   # Boolean
$item["Active"] = $false     # Boolean

# ❌ WRONG
$item["Processed"] = "True"  # String (may not work)

Issue: Workflow Runs Slowly

Symptoms: Workflow takes >300ms per item

Diagnosis: 1. Check if using CAML queries (faster) vs. filtering in PowerShell (slower) 2. Check if batching updates (should use ExecuteQuery() per batch, not per item) 3. Check network latency (if not localhost)

Optimization Tips:

# SLOW - Filter in PowerShell after loading all items
$allItems = Get-PnPListItem -List "MyList"
$pending = $allItems | Where-Object { $_["Status"] -eq "Pending" }

# FAST - Filter with CAML query
$caml = "<View><Query><Where><Eq><FieldRef Name='Status'/><Value Type='Text'>Pending</Value></Eq></Where></Query></View>"
$pending = Get-PnPListItem -List "MyList" -Query $caml

# SLOW - Execute per item
foreach ($item in $items) {
    $item.Update()
    $ctx.ExecuteQuery()  # ❌ One query per item
}

# FAST - Batch updates
foreach ($item in $items) {
    $item.Update()  # Queued
}
$ctx.ExecuteQuery()  # ✅ One query for all items


Testing Your Workflows

Unit Testing Checklist

Before running workflows in production, test these scenarios:

  • [ ] Connection - Workflow can connect to mock server
  • [ ] List Access - Can read workflow list
  • [ ] Item Creation - Can create new items
  • [ ] Item Updates - Can update existing items
  • [ ] Field Access - Can read/write all field types
  • [ ] CAML Queries - Filtered queries return correct results
  • [ ] State Transitions - State field updates correctly
  • [ ] Error Handling - Workflow handles missing items gracefully
  • [ ] Batch Processing - Can process 100+ items efficiently
  • [ ] Concurrent Workflows - Multiple workflows don't conflict

Performance Testing

Use this script to benchmark your workflow:

# Create test data
$itemCount = 1000
$list = Get-PnPList -Identity "TestList"

Write-Host "Creating $itemCount test items..."
for ($i = 1; $i -le $itemCount; $i++) {
    Add-PnPListItem -List $list -Values @{
        Title = "Test Item $i"
        Status = "Pending"
        Processed = $false
    }
}

# Measure workflow performance
$start = Get-Date
$items = Get-PnPListItem -List $list -Query "<View><Query><Where><Eq><FieldRef Name='Status'/><Value Type='Text'>Pending</Value></Eq></Where></Query></View>"

foreach ($item in $items) {
    $item["Status"] = "Processed"
    $item["Processed"] = $true
    $item.Update()
}
$ctx.ExecuteQuery()
$end = Get-Date

$duration = ($end - $start).TotalSeconds
$avgMs = ($duration / $itemCount) * 1000

Write-Host "Processed $itemCount items in $duration seconds"
Write-Host "Average: $avgMs ms per item"

Expected Results: - 100 items: <10 seconds (target: <100ms/item) - 1,000 items: <5 minutes (target: <300ms/item)


Production Deployment

Checklist

Before deploying Cesivi Server for kenaflow workflows:

  1. Configuration
  2. [ ] Set correct port in appsettings.json
  3. [ ] Configure storage provider (FileSystem or LiteDb)
  4. [ ] Set up authentication if needed
  5. [ ] Configure logging level

  6. Data Setup

  7. [ ] Create required lists (workflow list, config list, etc.)
  8. [ ] Create required fields (Status, Processed, etc.)
  9. [ ] Create test data for validation
  10. [ ] Set up lookup lists if needed

  11. Testing

  12. [ ] Run unit tests (see checklist above)
  13. [ ] Run performance tests
  14. [ ] Test error scenarios
  15. [ ] Validate with actual kenaflow workflows

  16. Monitoring

  17. [ ] Enable diagnostic logging
  18. [ ] Set up health checks (/health endpoint)
  19. [ ] Monitor performance metrics
  20. [ ] Review error logs regularly

Docker Deployment (Optional)

# docker-compose.yml
version: '3.8'
services:
  cesivi:
    image: cesivi-server:latest
    ports:
      - "5000:5000"
    volumes:
      - ./mockdata:/app/MockData
    environment:
      - Cesivi__Port=5000
      - Cesivi__StorageProvider=LiteDb

See DEPLOYMENT_GUIDE.md for complete deployment instructions.


Additional Resources


Support

For issues or questions: 1. Check Troubleshooting section above 2. Review Known Limitations 3. Check PNP_COMPATIBILITY.md for cmdlet-specific issues 4. File GitHub issue with: - Workflow configuration (sanitized) - Error messages - Server logs - Minimal reproduction script


Version History

Version Date Changes
1.0 2026-01-10 Initial guide based on PLAN-117 validation (94h testing)
2.0 2026-03-28 Updated to v200 baseline; CurrentUser identity fix (PLAN-777); 48/48 tests

This guide reflects the v200 baseline with 48/48 kenaflow tests passing. Production-Ready: ✅