This guide provides comprehensive instructions for setting up the Container Migration Solution Accelerator for local development across Windows and Linux platforms.
This application consists of three separate services that run independently:
- Processor - Handles migration logic (Queue Mode or Direct Mode)
- Backend API - REST API server for the frontend
- Frontend - React-based user interface
⚠️ Critical: Each service must run in its own terminal/console window
- Do NOT close terminals while services are running
- Open 3 separate terminal windows for local development
- Each service will occupy its terminal and show live logs
Terminal Organization:
- Terminal 1: Processor (Queue Mode) - Runs continuously, polls for messages
- Terminal 2: Backend API - HTTP server on port 8000
- Terminal 3: Frontend - Development server on port 5173
All paths in this guide are relative to the repository root directory:
Container-Migration-Solution-Accelerator/ ← Repository root (start here)
├── src/
│ ├── processor/
│ │ ├── .venv/
│ │ └── src/
│ │ ├── main.py ← Direct Mode entry point
│ │ ├── main_service.py ← Queue Mode entry point
│ │ └── .env ← Processor config file
│ ├── backend-api/
│ │ ├── .venv/ ← Virtual environment
│ │ └── src/app/
│ │ ├── main.py ← API entry point
│ │ └── .env ← Backend API config file
│ └── frontend/
│ ├── node_modules/
│ └── .env ← Frontend config file
└── docs/ ← Documentation (you are here)Before starting any step, ensure you are in the repository root directory:
# Verify you're in the correct location
pwd # Linux/macOS - should show: .../Container-Migration-Solution-Accelerator
Get-Location # Windows PowerShell - should show: ...\Container-Migration-Solution-Accelerator
# If not, navigate to repository root
cd path/to/Container-Migration-Solution-AcceleratorThis project uses separate .env files in each service directory with different configuration requirements:
- Processor:
src/processor/src/.env- Azure App Configuration URL - Backend API:
src/backend-api/src/app/.env- Azure App Configuration URL - Frontend:
src/frontend/.env- Azure AD authentication settings
When copying .env samples, always navigate to the specific service directory first.
# Install Python 3.12+ and Git
winget install Python.Python.3.12
winget install Git.Git
# Install Node.js for frontend
winget install OpenJS.NodeJS.LTS
# Install uv package manager
py -3.12 -m pip install uvNote: On Windows, use py -3.12 -m uv instead of uv for all commands to ensure you're using Python 3.12.
# Install WSL2 first (run in PowerShell as Administrator):
# wsl --install -d Ubuntu
# Then in WSL2 Ubuntu terminal:
sudo apt update && sudo apt install python3.12 python3.12-venv git curl nodejs npm -y
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.bashrc# Install prerequisites
sudo apt update && sudo apt install python3.12 python3.12-venv git curl nodejs npm -y
# Install uv package manager
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.bashrc# Install prerequisites
sudo dnf install python3.12 python3.12-devel git curl gcc nodejs npm -y
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
source ~/.bashrcgit clone https://github.com/microsoft/Container-Migration-Solution-Accelerator.git
cd Container-Migration-Solution-AcceleratorCreate .vscode/extensions.json in the workspace root and copy the following JSON:
{
"recommendations": [
"ms-python.python",
"ms-python.pylint",
"ms-python.black-formatter",
"ms-python.isort",
"ms-vscode-remote.remote-wsl",
"ms-vscode-remote.remote-containers",
"redhat.vscode-yaml",
"ms-vscode.azure-account",
"ms-python.mypy-type-checker"
]
}VS Code will prompt you to install these recommended extensions when you open the workspace.
Create .vscode/settings.json and copy the following JSON:
{
"python.defaultInterpreterPath": "./.venv/bin/python",
"python.terminal.activateEnvironment": true,
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"files.associations": {
"*.yaml": "yaml",
"*.yml": "yaml"
}
}
⚠️ Important: Before proceeding, you must deploy the Azure infrastructure that the local services connect to (App Configuration, Cosmos DB, Storage Account, AI Services, etc.). The local services do not run standalone — they require deployed Azure resources.
If you haven't already deployed the infrastructure, follow the Deployment Guide or run:
# Authenticate with Azure Developer CLI
azd auth login
# Deploy infrastructure and application
azd upDuring azd up, you'll be prompted for environment name, subscription, region, and resource group. After deployment completes (~5-7 minutes), note the resource group name — you'll need it for the next steps.
Note: You only need the infrastructure deployed. For local development, you'll run the Processor, Backend API, and Frontend locally instead of using the deployed Container Apps.
Before configuring services, authenticate with Azure:
# Login to Azure CLI
az login
# Set your subscription
az account set --subscription "your-subscription-id"
# Verify authentication
az account showNavigate to your resource group and select the resource with prefix appcs- to get the configuration URL:
APP_CONFIGURATION_URL=https://[Your app configuration service name].azconfig.ioFor reference, see the image below:

To run the application locally, your Azure account needs the following role assignments on the deployed resources:
Linux/macOS:
# Get your principal ID
PRINCIPAL_ID=$(az ad signed-in-user show --query id -o tsv)
# Assign App Configuration Data Reader role
az role assignment create \
--assignee $PRINCIPAL_ID \
--role "App Configuration Data Reader" \
--scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.AppConfiguration/configurationStores/<appconfig-name>"Windows PowerShell:
# Get your principal ID
$PRINCIPAL_ID = az ad signed-in-user show --query id -o tsv
# Assign App Configuration Data Reader role
az role assignment create --assignee $PRINCIPAL_ID --role "App Configuration Data Reader" --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.AppConfiguration/configurationStores/<appconfig-name>"Linux/macOS:
# Assign Cosmos DB Built-in Data Contributor role
az cosmosdb sql role assignment create \
--account-name <cosmos-account-name> \
--resource-group <resource-group> \
--role-definition-name "Cosmos DB Built-in Data Contributor" \
--principal-id $PRINCIPAL_ID \
--scope "/"Windows PowerShell:
az cosmosdb sql role assignment create --account-name <cosmos-account-name> --resource-group <resource-group> --role-definition-name "Cosmos DB Built-in Data Contributor" --principal-id $PRINCIPAL_ID --scope "/"Depending on the features you use, you may also need:
- Storage Blob Data Contributor - For Azure Storage operations
- Storage Queue Data Contributor - For queue-based processing
- Azure OpenAI User - For AI model access
Note: RBAC permission changes can take 5-10 minutes to propagate. If you encounter "Forbidden" errors after assigning roles, wait a few minutes and try again.
📋 Terminal Reminder: Open a dedicated terminal window (Terminal 1) for the Processor service. All commands in this section assume you start from the repository root directory.
The Processor handles the actual migration logic and can run in two modes:
- Queue-based mode (
main_service.py): Processes migration requests from Azure Storage Queue (production) - Direct execution mode (
main.py): Runs migrations directly without queue (development/testing)
cd src/processorCreate a .env file in the src/processor/src directory (NOT in src/processor root).
You can copy the example file as a starting point, then move it to the correct location:
# Linux/macOS
cp .env.example src/.env
# Windows PowerShell
Copy-Item .env.example src\.envEdit src/.env and set the App Configuration URL:
APP_CONFIGURATION_URL=https://[Your app configuration service name].azconfig.io
⚠️ Important: The.envfile must be located insrc/processor/src/directory, not insrc/processor/root. The application looks for the.envfile in the same directory asmain.pyandmain_service.py.
# Create and activate virtual environment
uv venv .venv
# Activate virtual environment
source .venv/bin/activate # Linux/WSL2
# or
.\.venv\Scripts\Activate.ps1 # Windows PowerShell
# Install dependencies
uv sync --python 3.12Windows users: If you encounter issues with the uv command not being found, use the Python Launcher instead:
# Create virtual environment
py -3.12 -m uv venv .venv
# Install dependencies
py -3.12 -m uv sync --python 3.12
⚠️ Important: Always runuv sync(orpy -3.12 -m uv syncon Windows) after creating the virtual environment to install all required dependencies. Missing dependencies will cause runtime errors likeModuleNotFoundError: No module named 'pydantic'or DNS resolution failures.
Process migration requests from Azure Storage Queue:
Important: This mode requires the Storage Queue Data Contributor role on the Azure Storage Account. Assign it using:
Linux/macOS:
# Get your principal ID and subscription ID
PRINCIPAL_ID=$(az ad signed-in-user show --query id -o tsv)
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
# Assign Storage Queue Data Contributor role
az role assignment create \
--role "Storage Queue Data Contributor" \
--assignee $PRINCIPAL_ID \
--scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account-name>"Windows PowerShell:
$PRINCIPAL_ID = az ad signed-in-user show --query id -o tsv
$SUBSCRIPTION_ID = az account show --query id -o tsv
az role assignment create --role "Storage Queue Data Contributor" --assignee $PRINCIPAL_ID --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account-name>"Note: Permission changes take 5-10 minutes to propagate.
Run the queue service:
cd src
python main_service.pyThis mode provides:
- Automatic retry logic with exponential backoff
- Production-ready error handling
- Message polling with "No messages in main queue" logs
Run migrations directly without queue infrastructure:
cd src
python main.pyThis mode is useful for:
- Running single migrations
- Debugging migration logic
- Quick testing without queue setup
📋 Terminal Reminder: Open a second dedicated terminal window (Terminal 2) for the Backend API. Keep Terminal 1 (Processor) running. All commands assume you start from the repository root directory.
The Backend API provides REST endpoints for the frontend and handles API requests.
# From repository root
cd src/backend-apiCreate a .env file in the src/backend-api/src/app directory:
cd src/app
# Copy the example file
cp .env.example .env # Linux
# or
Copy-Item .env.example .env # Windows PowerShellEdit the .env file and set the App Configuration URL (same value as the Processor):
APP_CONFIGURATION_URL=https://[Your app configuration service name].azconfig.io# Navigate back to backend-api root
cd ../..
# Create and activate virtual environment
uv venv .venv
# Activate virtual environment
source .venv/bin/activate # Linux/WSL2
# or
.\.venv\Scripts\Activate.ps1 # Windows PowerShell
# Install dependencies
uv sync --python 3.12# Make sure you're in the backend-api/src/app directory
cd src/app
# Run with uvicorn
python -m uvicorn main:app --host 0.0.0.0 --port 8000
⚠️ Windows Note: Do not use the--reloadflag on Windows. The file watcher monitors.venvdirectories and causes repeated crash loops. If you need auto-reload on Linux/macOS, use:python -m uvicorn main:app --reload --reload-exclude ".venv" --host 0.0.0.0 --port 8000
The Backend API will start at:
- API:
http://localhost:8000 - API Documentation:
http://localhost:8000/docs
📋 Terminal Reminder: Open a third dedicated terminal window (Terminal 3) for the Frontend. Keep Terminals 1 (Processor) and 2 (Backend API) running. All commands assume you start from the repository root directory.
The UI is located under src/frontend.
# From repository root
cd src/frontendnpm installCreate a .env file in the src/frontend directory:
# Copy the example file
cp .env.example .env # Linux
# or
Copy-Item .env.example .env # Windows PowerShellEdit the .env file with your Azure AD configuration:
# Required: Your Azure AD app registration client ID (frontend app registration)
VITE_APP_WEB_CLIENT_ID=your-frontend-client-id-here
# Required: Your Azure AD tenant authority
VITE_APP_WEB_AUTHORITY=https://login.microsoftonline.com/your-tenant-id
# Optional: Redirect URLs (defaults to current origin)
VITE_APP_REDIRECT_URL=http://localhost:5173
VITE_APP_POST_REDIRECT_URL=http://localhost:5173
# Required: Scopes for login and token acquisition
# Use the user_impersonation scope from your app registrations
VITE_APP_WEB_SCOPE=api://your-frontend-client-id/user_impersonation
VITE_APP_API_SCOPE=api://your-backend-api-client-id/user_impersonation
# Required: Backend API URL
VITE_API_URL=http://localhost:8000/api
# Required: Enable/disable MSAL authentication
# Set to "false" for local development without Azure AD login
# Set to "true" to enable Azure AD authentication
VITE_ENABLE_AUTH=false
⚠️ Important Notes:
VITE_ENABLE_AUTHcontrols authentication:
- Set to
falseto bypass Azure AD login and access the UI directly (easiest for local dev)- Set to
trueif you need to test the full MSAL authentication flow- The deployed app always uses authentication; this setting is for local development convenience
Scope Configuration:
- The
user_impersonationscope is created automatically duringazd updeployment- Find your client IDs in Azure Portal → App registrations (look for
ca-frontend-*andca-backend-api-*)- See ConfigureAppAuthentication.md for detailed setup
App Registration for Authentication (if
VITE_ENABLE_AUTH=true):
- Go to Azure Portal → Microsoft Entra ID → App registrations → Your frontend app
- Under Authentication, add a Single-page application (SPA) platform
- Add redirect URI:
http://localhost:5173- Click Save
Common Error: AADSTS900561
- If you see "The endpoint only accepts POST requests. Received a GET request"
- Ensure the platform type is Single-page application (SPA), not "Web"
- Clear browser cache or use incognito mode after fixing
Restart Required:
- After updating
.env, stop and restart the frontend dev server (npm run dev)- Vite caches environment variables at startup and won't pick up changes until restarted
npm run devNote: You do not need to run
npm run buildfor local development.npm run devstarts a development server with hot module replacement (HMR).
The app will start at:
http://localhost:5173
(or whichever port Vite assigns)
# Check available Python versions
python3 --version
python3.12 --version
# If python3.12 not found, install it:
# Ubuntu: sudo apt install python3.12
# Windows: winget install Python.Python.3.12# Recreate virtual environment
rm -rf .venv # Linux
# or Remove-Item -Recurse .venv # Windows PowerShell
uv venv .venv
# Activate and reinstall
source .venv/bin/activate # Linux
# or .\.venv\Scripts\Activate.ps1 # Windows
uv sync --python 3.12# Fix ownership of files
sudo chown -R $USER:$USER .
# Fix uv permissions
chmod +x ~/.local/bin/uv# PowerShell execution policy
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Long path support (Windows 10 1607+, run as Administrator)
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
# SSL certificate issues
pip install --trusted-host pypi.org --trusted-host pypi.python.org --trusted-host files.pythonhosted.org uv# Check environment variables are loaded
env | grep AZURE # Linux
Get-ChildItem Env:AZURE* # Windows PowerShell
# Validate .env file format
cat .env | grep -v '^#' | grep '=' # Should show key=value pairsBefore using the application, confirm all three services are running in separate terminals:
| Terminal | Service | Working Directory | Command | Expected Output | URL |
|---|---|---|---|---|---|
| Terminal 1 | Processor (Queue Mode) | src/processor/src |
python main_service.py |
INFO: No messages in main queue (repeating every 5s) |
N/A |
| Terminal 2 | Backend API | src/backend-api/src/app |
python -m uvicorn main:app --host 0.0.0.0 --port 8000 |
INFO: Application startup complete |
http://localhost:8000 |
| Terminal 3 | Frontend | src/frontend |
npm run dev |
Local: http://localhost:5173/ |
http://localhost:5173 |
1. Check Backend API:
# In a new terminal (Terminal 4)
curl http://localhost:8000/health
# Expected: {"message":"I'm alive!"}2. Check Frontend:
- Open browser to http://localhost:5173
- Should see the Container Migration UI
- If authentication is configured, you'll be redirected to Azure AD login
3. Check Processor:
- Look at Terminal 1 output
- Should see regular polling messages:
INFO: No messages in main queue - No error messages
Service not starting?
- Ensure you're in the correct directory
- Verify virtual environment is activated (Python services)
- Check that port is not already in use (8000 for API, 5173 for frontend)
- Review error messages in the terminal
Can't access services?
- Verify firewall isn't blocking ports 8000 or 5173
- Try
http://localhost:portinstead ofhttp://127.0.0.1:port - Ensure services show "startup complete" messages
Once all services are running (as confirmed in Step 8), you can:
- Access the Application: Open
http://localhost:5173in your browser to explore the frontend UI - Try a Sample Workflow: Follow SampleWorkflow.md for a guided walkthrough of the migration process
- Explore the Codebase: Start with
src/processor/src/main_service.pyto understand the agent architecture - Customize Agents: Follow CustomizeExpertAgents.md to modify agent behavior
- Extend Platform Support: Follow ExtendPlatformSupport.md to add new cloud platforms
- Deployment Guide - Production deployment instructions
- Technical Architecture - System architecture overview
- Extending Platform Support - Adding new platform support
- Configuring MCP Servers - MCP server configuration
- Multi-Agent Orchestration - Agent collaboration patterns