Skip to content

Migration Orchestrator App

Date: 2026-02-26 Status: PLANNED Priority: Side Project (parallel to main migration work)


Vision

A desktop/web application that allows configuring and running multiple Umbraco v8→v17 database migrations simultaneously, with real-time progress monitoring.

Phase 1: Blazor Server web app (localhost during development) Phase 2: Publish online (Azure/server deployment with authentication)


Core Features

1. Project Configuration

Each "project" represents one credit union client migration:

Field Description Example
Project Name Human-friendly identifier progresscu.ie
Source DB Connection v8 Umbraco database Server=cb-sql.double.pt,7071;Database=progresscu.ie;...
Target DB Connection v17 Umbraco database Server=localhost;Database=dbl_progress_cms;...
Source Project Path v8 project folder (for media detection) C:\repos\progress\psCreditUnion
Forms Source Path Umbraco Forms data folder (if applicable) C:\repos\progress\psCreditUnion\App_Data\UmbracoForms
Forms Destination Where to copy migrated forms C:\repos\progress\dbl.Progress\src\www\umbraco\Data\UmbracoForms
Batch Size Bulk operation batch size 1000 (default)
Parallel Degree Internal parallelism 4 (default)
Max Memory MB Memory limit 2048 (default)
Timeout Seconds DB command timeout 300 (default)
Skip Content Skip content migration false
Skip Media Skip media migration false
Skip Members Skip member migration false

Projects are saved to a JSON config file for persistence between sessions.

2. Migration Execution

  • Run Single — Execute one project's migration
  • Run All — Execute all configured projects in parallel
  • Run Selected — Execute selected projects in parallel
  • Each migration runs as a separate process (process-level isolation)
  • Cancel button per migration

3. Progress Monitoring

Real-time display per migration: - Current step (e.g., "Migrating Property Values — Step 17/19") - Progress bar (% complete based on step count or node count) - Elapsed time - Log output (tail of log file) - Status: Queued / Running / Completed / Failed / Cancelled

4. Pre/Post Migration Actions

Configurable per project: - Pre-migration: Drop target tables + restart Umbraco (current run-migrations.ps1 behavior) - Post-migration: Run verification queries, generate report


Technical Architecture

Phase 1: Windows App (Blazor Hybrid or WPF)

Progress.MigrationOrchestrator/
├── Progress.MigrationOrchestrator.sln
├── src/
│   ├── Progress.MigrationOrchestrator.Core/     # Shared logic
│   │   ├── Models/
│   │   │   ├── MigrationProject.cs              # Project config model
│   │   │   ├── MigrationRun.cs                  # Run state/progress
│   │   │   └── MigrationStep.cs                 # Step definitions
│   │   ├── Services/
│   │   │   ├── IMigrationRunner.cs              # Process orchestration interface
│   │   │   ├── ProcessMigrationRunner.cs         # Spawns UmbracoMigrator processes
│   │   │   ├── IProjectStore.cs                 # Project config persistence
│   │   │   ├── JsonProjectStore.cs              # JSON file storage
│   │   │   └── LogTailService.cs                # Real-time log file monitoring
│   │   └── Extensions/
│   │       └── ServiceCollectionExtensions.cs
│   │
│   ├── Progress.MigrationOrchestrator.App/       # Desktop app (Blazor Hybrid / MAUI)
│   │   ├── Components/
│   │   │   ├── ProjectList.razor                # List/add/edit projects
│   │   │   ├── ProjectForm.razor                # Project configuration form
│   │   │   ├── MigrationDashboard.razor         # Run + monitor migrations
│   │   │   ├── MigrationProgress.razor          # Per-migration progress card
│   │   │   └── LogViewer.razor                  # Real-time log output
│   │   └── Program.cs
│   │
│   └── Progress.MigrationOrchestrator.Web/       # Phase 2: Blazor Server web app
│       ├── Components/ (same Razor components)
│       └── Program.cs

Key Design Decisions

Process Isolation (not in-process) Each migration runs as a separate UmbracoMigrator.exe process because: - No code changes needed to the migration tool - Natural memory/state isolation - Failure in one migration can't corrupt others - Easy to kill/cancel individual migrations

Progress Tracking via Log Parsing The migration tool already logs each step. Parse log output in real-time:

[12:34:56] Step 1/19: Migrating Users...
[12:34:57] Step 1/19: Migrating Users... DONE (142 users, 1.2s)
[12:34:57] Step 2/19: Migrating Languages...

Configuration Persistence

// migrations.json
{
  "projects": [
    {
      "id": "progresscu",
      "name": "Progress CU (Ireland)",
      "sourceConnection": "Server=...;Database=progresscu.ie;...",
      "targetConnection": "Server=...;Database=dbl_progress_cms;...",
      "sourceProjectPath": "C:\\repos\\progress\\psCreditUnion",
      "formsSourcePath": "C:\\repos\\progress\\psCreditUnion\\App_Data\\UmbracoForms",
      "formsDestinationPath": "...",
      "options": {
        "batchSize": 1000,
        "parallelDegree": 4,
        "maxMemoryMB": 2048,
        "timeoutSeconds": 300,
        "force": true
      }
    }
  ]
}


Implementation Approach

Why Blazor Server: - Single project, simplest architecture - Runs as localhost:5050 during development — functions as a "local app" - Directly publishable online when ready (Azure App Service, Docker, etc.) - No MAUI dependency - .NET 10, same toolchain as the migration tool - Rich UI with CSS/HTML, real-time updates via SignalR (built-in) - Can access local file system for log files and project paths

Phase 1→2 transition: - Add authentication (Azure AD / simple auth) - Deploy to Azure App Service or Docker - Replace local file paths with configurable storage paths - Add multi-user support if needed


ProcessMigrationRunner Design

public class ProcessMigrationRunner : IMigrationRunner
{
    public async Task<MigrationRun> StartMigrationAsync(MigrationProject project)
    {
        var run = new MigrationRun(project);
        var logFile = Path.Combine(logsDir, $"{project.Id}-{DateTime.Now:yyyyMMdd-HHmmss}.log");

        var args = new StringBuilder();
        args.Append($"migrate");
        args.Append($" -s \"{project.SourceConnection}\"");
        args.Append($" -t \"{project.TargetConnection}\"");
        args.Append($" --log-file \"{logFile}\"");
        args.Append($" --batch-size {project.Options.BatchSize}");
        args.Append($" --parallel-degree {project.Options.ParallelDegree}");
        args.Append($" --force");

        if (!string.IsNullOrEmpty(project.SourceProjectPath))
            args.Append($" --source-project-path \"{project.SourceProjectPath}\"");
        if (!string.IsNullOrEmpty(project.FormsSourcePath))
            args.Append($" --forms-source-path \"{project.FormsSourcePath}\"");

        var process = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = migrationToolPath,
                Arguments = args.ToString(),
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            }
        };

        process.OutputDataReceived += (s, e) => run.AppendLog(e.Data);
        process.ErrorDataReceived += (s, e) => run.AppendError(e.Data);

        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        run.Process = process;
        run.LogFile = logFile;
        run.Status = MigrationStatus.Running;

        return run;
    }
}

Migration Tool Changes Needed

The migration tool itself needs minimal changes to support the orchestrator:

1. Structured Progress Output (nice-to-have)

Add --progress-format json CLI option that outputs machine-parseable progress:

{"step": 1, "total": 19, "name": "Migrating Users", "status": "started", "timestamp": "2026-02-26T12:34:56Z"}
{"step": 1, "total": 19, "name": "Migrating Users", "status": "completed", "count": 142, "duration": "1.2s"}

This makes progress parsing reliable instead of log regex.

2. Forms Migration Parameters

Verify these CLI options exist (or add them): - --forms-source-path — Path to v8 Umbraco Forms data - --forms-destination-path — Path to v17 Forms data folder

3. Exit Codes

Ensure proper exit codes: - 0 = Success - 1 = Migration failed - 2 = Validation failed - 3 = Cancelled


Effort Estimate

Component Effort
Core models + project store 0.5 day
ProcessMigrationRunner 1 day
LogTailService + progress parsing 0.5 day
Blazor UI components (ProjectList, Form, Dashboard) 1.5 days
Real-time progress (SignalR/FileSystemWatcher) 0.5 day
Testing + polish 1 day
Total Phase 1 (desktop/local web) ~5 days
Phase 2 (web publish + auth) +3 days
Migration tool --progress-format json +0.5 day

Forms Migration Research Needed

Before implementing, verify: 1. Does the current migration tool handle Umbraco Forms migration? 2. What CLI parameters does it accept for Forms? 3. Is Forms data stored in files or DB in v8? (v8 uses App_Data files by default) 4. How does v17 Forms store data? (DB-based in v17)

Check --forms-source-path parameter in MigrationOptions.cs.

Migration documentation by Double for Progress Credit Union