1"use strict";(self.webpackChunkhomol_works=self.webpackChunkhomol_works||[]).push([[5884],{85708(e,r,t){t.r(r),t.d(r,{default:()=>o,metadata:()=>s});var s=t(3825),n=t(74848),i=t(28453);const a={authorsImageUrls:[void 0]};function l(e){const r={code:"code",h2:"h2",h3:"h3",li:"li",mermaid:"mermaid",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.p,{children:"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 \u2014 so a multi-app modernization engagement can load phased work items instead of debating a static file."}),"\n",(0,n.jsx)(r.h2,{id:"what-happened",children:"What happened"}),"\n",(0,n.jsx)(r.h3,{id:"planned-architecture-discussion-grade",children:"Planned architecture (discussion-grade)"}),"\n",(0,n.jsx)(r.p,{children:"Married the system design with the Azure architecture into a living trajectory the team can share:"}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"API-first, location-driven platform"})," \u2014 one Azure SQL system of record, document binaries in Azure Blob (SQL keeps metadata / ",(0,n.jsx)(r.code,{children:"blob_uri"}),"), shared .NET API behind API Management"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Three clients, one API"})," \u2014 internal React SPA, offline-capable field app (.NET MAUI + SQLite sync), and an external React portal (Entra External ID + accessibility expectations)"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Scriptable Azure baseline"})," \u2014 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"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Auth split"})," \u2014 Entra ID for internal users; Entra External ID for portal users"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Integrations later in the sequence"})," \u2014 payments, HR feed, insurer file drop, addressing, notifications \u2014 after core domain and apps stand up"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Migration + hardening"})," as late phases \u2014 cutover from the legacy permitting platform, then security/docs/go-live"]}),"\n"]}),"\n",(0,n.jsx)(r.p,{children:"Nothing here claims a finished production tenant; it is the kickoff architecture the backlog is sequenced against."}),"\n",(0,n.jsx)(r.h3,{id:"delivery-phases",children:"Delivery phases"}),"\n",(0,n.jsxs)(r.p,{children:["Sequencing is ",(0,n.jsx)(r.strong,{children:"P0\u2013P10"})," (~16-month build). Phases are delivery order labels \u2014 not ADO Epics:"]}),"\n",(0,n.jsxs)(r.table,{children:[(0,n.jsx)(r.thead,{children:(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.th,{children:"Code"}),(0,n.jsx)(r.th,{children:"Phase"}),(0,n.jsx)(r.th,{children:"Intent"})]})}),(0,n.jsxs)(r.tbody,{children:[(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P0"}),(0,n.jsx)(r.td,{children:"Discovery & UX/data design"}),(0,n.jsx)(r.td,{children:"Requirements depth, mocks, SQL + Blob layout"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P1"}),(0,n.jsx)(r.td,{children:"Azure platform & IaC"}),(0,n.jsx)(r.td,{children:"Scriptable baseline resources"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P2"}),(0,n.jsx)(r.td,{children:"Data model & API core"}),(0,n.jsx)(r.td,{children:"Location-first anchors, OpenAPI, auth"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P3"}),(0,n.jsx)(r.td,{children:"Main app shell"}),(0,n.jsx)(r.td,{children:"Internal React Static Web App framework"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P4"}),(0,n.jsx)(r.td,{children:"Domain capabilities"}),(0,n.jsx)(r.td,{children:"Licensing, plan review, inspections, complaints, fiscal"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P5"}),(0,n.jsx)(r.td,{children:"Field / inspectors app"}),(0,n.jsx)(r.td,{children:"Offline MAUI + sync"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P6"}
1),(0,n.jsx)(r.td,{children:"External portal"}),(0,n.jsx)(r.td,{children:"Public React + External ID"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P7"}),(0,n.jsx)(r.td,{children:"Integrations"}),(0,n.jsx)(r.td,{children:"Payments, HR, file drops, notifications, addressing"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P8"}),(0,n.jsx)(r.td,{children:"Migration"}),(0,n.jsx)(r.td,{children:"Legacy platform \u2192 new system"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P9"}),(0,n.jsx)(r.td,{children:"Reporting & BI"}),(0,n.jsx)(r.td,{children:"Analytics (decision pending)"})]}),(0,n.jsxs)(r.tr,{children:[(0,n.jsx)(r.td,{children:"P10"}),(0,n.jsx)(r.td,{children:"Hardening & cutover"}),(0,n.jsx)(r.td,{children:"Security, runbooks, go-live"})]})]})]}),"\n",(0,n.jsx)(r.mermaid,{value:"flowchart TD\n P0[P0 Discovery] --\x3e P1[P1 Azure_IaC] --\x3e P2[P2 Data_API] --\x3e P3[P3 Main_shell] --\x3e P4[P4 Domain]\n P2 --\x3e P5[P5 Field_app]\n P2 --\x3e P6[P6 Portal]\n P4 --\x3e P7[P7 Integrations]\n P5 --\x3e P7\n P6 --\x3e P7\n P4 --\x3e P8[P8 Migration]\n P7 --\x3e P9[P9 Reporting]\n P8 --\x3e P10[P10 Cutover]\n P9 --\x3e P10"}),"\n",(0,n.jsx)(r.h3,{id:"from-estimate-sheet-to-picklist",children:"From estimate sheet to picklist"}),"\n",(0,n.jsxs)(r.p,{children:["Started from the ",(0,n.jsx)(r.strong,{children:"original estimating backlog"})," (archived workbook \u2014 not reproduced in detail here). Ran a ",(0,n.jsx)(r.strong,{children:"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."]}),"\n",(0,n.jsxs)(r.p,{children:["Final picklist: ",(0,n.jsx)(r.strong,{children:"238 user stories"})," \u2014 ",(0,n.jsx)(r.strong,{children:"214"})," from the estimating backlog and ",(0,n.jsx)(r.strong,{children:"24"})," gap stories."]}),"\n",(0,n.jsx)(r.h3,{id:"how-azure-devops-sees-it",children:"How Azure DevOps sees it"}),"\n",(0,n.jsxs)(r.p,{children:["Hierarchy is ",(0,n.jsx)(r.strong,{children:"Epic \u2192 Feature \u2192 User Story"})," under one existing endeavor Epic (client project names stay private):"]}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Features"})," = durable ",(0,n.jsx)(r.strong,{children:"solution layers"})," (Infrastructure, API, Internal SPA, External SPA, MAUI, Integrations, Migration, Reporting, Program & delivery, \u2026) \u2014 not one Feature per phase"]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.strong,{children:"Tags"})," = delivery sequence (",(0,n.jsx)(r.code,{children:"Phase-P0"})," \u2026 ",(0,n.jsx)(r.code,{children:"Phase-P10"}),"), layer markers, which app slice owns the story, and ",(0,n.jsx)(r.code,{children:"Source-Backlog"})," vs ",(0,n.jsx)(r.code,{children:"Source-Gap"})]}),"\n",(0,n.jsx)(r.li,{children:"A generator script regenerates the CSV pack when discovery notes change; the import is a single hierarchical CSV for Boards \u2192 Import Work Items"}),"\n"]}),"\n",(0,n.jsx)(r.h3,{id:"obfuscated-picklist-sample",children:"Obfuscated picklist sample"}),"\n",(0,n.jsx)(r.p,{children:"A thin slice of Infrastructure / early-platform stories (titles lightly generalized; tags show the real shape):"}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-text",children:"Feature | User Story | Tags (abbrev.)\nInfrastructure | Set up technical work environments (Azure, DevOps, \u2026) | Phase-P1; Layer-Infrastructure; Source-Backlog\nInfrastructure | Scaffold PowerShell + Azure CLI + JSON resource manifest| Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Provision Key Vault and wire secret references | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Provision Application Insights / Monitor baseline | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Configure Entra ID for internal app + API | Phase-P1; Layer-Infrastructure;
1 Source-Gap\nInfrastructure | Configure Entra External ID for portal users | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Provision Azure SQL (dev) via IaC scripts | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Provision APIM + App Service for .NET API | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Provision Static Web Apps stubs (main + portal) | Phase-P1; Layer-Infrastructure; Source-Gap\nInfrastructure | Add GitHub Actions CI skeleton for API and web apps | Phase-P1; Layer-Infrastructure; Source-Gap\n"})}),"\n",(0,n.jsx)(r.p,{children:"Gap items (like the IaC scaffold row) are the architecture calling things the estimate sheet never named \u2014 exactly why the gap pass matters before import."})]})}function o(e={}){const{wrapper:r}={...(0,i.R)(),...e.components};return r?(0,n.jsx)(r,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}t.d(r,["assets",0,a,"contentTitle",0,void 0,"frontMatter",0,{id:"2026-08-03-ado-backlog-import-pack",title:"From Discovery Notes to an ADO Import Pack",author:"Mike Homol",author_title:"Principal Consultant @ ThreeWill",author_url:"https://github.com/mhomol",author_image_url:"https://avatars2.githubusercontent.com/u/680566?s=460&v=4",tags:["ai","cursor","azure-devops","delivery"]},"toc",0,[{value:"What happened",id:"what-happened",level:2},{value:"Planned architecture (discussion-grade)",id:"planned-architecture-discussion-grade",level:3},{value:"Delivery phases",id:"delivery-phases",level:3},{value:"From estimate sheet to picklist",id:"from-estimate-sheet-to-picklist",level:3},{value:"How Azure DevOps sees it",id:"how-azure-devops-sees-it",level:3},{value:"Obfuscated picklist sample",id:"obfuscated-picklist-sample",level:3}]])},28453(e,r,t){t.d(r,{R:()=>a,x:()=>l});var s=t(96540);const n={},i=s.createContext(n);function a(e){const r=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(r):{...r,...e}},[r,e])}function l(e){let r;return r=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:a(e.components),s.createElement(i.Provider,{value:r},e.children)}},3825(e){e.exports=JSON.parse('{"permalink":"/blog/2026/08/03/ado-backlog-import-pack","source":"@site/blog/2026-08-03-ado-backlog-import-pack.md","title":"From Discovery Notes to an ADO Import Pack","description":"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 \u2014 so a multi-app modernization engagement can load phased work items instead of debating a static file.","date":"2026-08-03T00:00:00.000Z","tags":[{"inline":true,"label":"ai","permalink":"/blog/tags/ai"},{"inline":true,"label":"cursor","permalink":"/blog/tags/cursor"},{"inline":true,"label":"azure-devops","permalink":"/blog/tags/azure-devops"},{"inline":true,"label":"delivery","permalink":"/blog/tags/delivery"}],"readingTime":3.54,"hasTruncateMarker":false,"authors":[{"name":"Mike Homol","title":"Principal Consultant @ ThreeWill","url":"https://github.com/mhomol","imageURL":"https://avatars2.githubusercontent.com/u/680566?s=460&v=4","key":null,"page":null}],"frontMatter":{"id":"2026-08-03-ado-backlog-import-pack","title":"From Discovery Notes to an ADO Import Pack","author":"Mike Homol","author_title":"Principal Consultant @ ThreeWill","author_url":"https://github.com/mhomol","author_image_url":"https://avatars2.githubusercontent.com/u/680566?s=460&v=4","tags":["ai","cursor","azure-devops","delivery"]},"unlisted":false,"prevItem":{"title":"Weekly AI Builds - August 10, 2026","permalink":"/blog/2026/08/10/weekly-ai-builds"},"nextItem":{"title":"Weekly AI Builds - August 3, 2026","permalink":"/blog/2026/08/03/weekly-ai-builds"}}')}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.