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¶
Recommended: Blazor Server from Day 1¶
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.