Skip to main content

One post tagged with "azure-devops"

View All Tags

From Discovery Notes to an ADO Import Pack

· 4 min read
Mike Homol
Principal Consultant @ ThreeWill

Discovery backlogs often die as sprawling spreadsheets. This week I turned a kickoff architecture, an estimating sheet, and a gap analysis into an Azure DevOps import pack — so a multi-app modernization engagement can load phased work items instead of debating a static file.

What happened

Planned architecture (discussion-grade)

Married the system design with the Azure architecture into a living trajectory the team can share:

  • API-first, location-driven platform — one Azure SQL system of record, document binaries in Azure Blob (SQL keeps metadata / blob_uri), shared .NET API behind API Management
  • Three clients, one API — internal React SPA, offline-capable field app (.NET MAUI + SQLite sync), and an external React portal (Entra External ID + accessibility expectations)
  • Scriptable Azure baseline — PowerShell orchestrating Azure CLI against a JSON resource manifest (Key Vault, App Insights, SQL, App Service, Functions, Static Web Apps stubs, Communication Services) in a single primary resource group
  • Auth split — Entra ID for internal users; Entra External ID for portal users
  • Integrations later in the sequence — payments, HR feed, insurer file drop, addressing, notifications — after core domain and apps stand up
  • Migration + hardening as late phases — cutover from the legacy permitting platform, then security/docs/go-live

Nothing here claims a finished production tenant; it is the kickoff architecture the backlog is sequenced against.

Delivery phases

Sequencing is P0–P10 (~16-month build). Phases are delivery order labels — not ADO Epics:

CodePhaseIntent
P0Discovery & UX/data designRequirements depth, mocks, SQL + Blob layout
P1Azure platform & IaCScriptable baseline resources
P2Data model & API coreLocation-first anchors, OpenAPI, auth
P3Main app shellInternal React Static Web App framework
P4Domain capabilitiesLicensing, plan review, inspections, complaints, fiscal
P5Field / inspectors appOffline MAUI + sync
P6External portalPublic React + External ID
P7IntegrationsPayments, HR, file drops, notifications, addressing
P8MigrationLegacy platform → new system
P9Reporting & BIAnalytics (decision pending)
P10Hardening & cutoverSecurity, runbooks, go-live
flowchart TD
P0[P0 Discovery] --> P1[P1 Azure_IaC] --> P2[P2 Data_API] --> P3[P3 Main_shell] --> P4[P4 Domain]
P2 --> P5[P5 Field_app]
P2 --> P6[P6 Portal]
P4 --> P7[P7 Integrations]
P5 --> P7
P6 --> P7
P4 --> P8[P8 Migration]
P7 --> P9[P9 Reporting]
P8 --> P10[P10 Cutover]
P9 --> P10

From estimate sheet to picklist

Started from the original estimating backlog (archived workbook — not reproduced in detail here). Ran a gap analysis against the architecture so platform, IaC, auth, observability, and other design-driven work that never appeared as estimating line items still landed as stories.

Final picklist: 238 user stories214 from the estimating backlog and 24 gap stories.

How Azure DevOps sees it

Hierarchy is Epic → Feature → User Story under one existing endeavor Epic (client project names stay private):

  • Features = durable solution layers (Infrastructure, API, Internal SPA, External SPA, MAUI, Integrations, Migration, Reporting, Program & delivery, …) — not one Feature per phase
  • Tags = delivery sequence (Phase-P0Phase-P10), layer markers, which app slice owns the story, and Source-Backlog vs Source-Gap
  • A generator script regenerates the CSV pack when discovery notes change; the import is a single hierarchical CSV for Boards → Import Work Items

Obfuscated picklist sample

A thin slice of Infrastructure / early-platform stories (titles lightly generalized; tags show the real shape):

Feature | User Story | Tags (abbrev.)
Infrastructure | Set up technical work environments (Azure, DevOps, …) | Phase-P1; Layer-Infrastructure; Source-Backlog
Infrastructure | Scaffold PowerShell + Azure CLI + JSON resource manifest| Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Provision Key Vault and wire secret references | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Provision Application Insights / Monitor baseline | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Configure Entra ID for internal app + API | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Configure Entra External ID for portal users | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Provision Azure SQL (dev) via IaC scripts | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Provision APIM + App Service for .NET API | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Provision Static Web Apps stubs (main + portal) | Phase-P1; Layer-Infrastructure; Source-Gap
Infrastructure | Add GitHub Actions CI skeleton for API and web apps | Phase-P1; Layer-Infrastructure; Source-Gap

Gap items (like the IaC scaffold row) are the architecture calling things the estimate sheet never named — exactly why the gap pass matters before import.