Create azure-devops.html

D David Veksler · 1 year ago 0159984349e48e1f4c5cb5e2bd9182c589425325
Parent: 3fadb28f9

1 file changed +768 −0

Diff

diff --git a/azure-devops.html b/azure-devops.html
new file mode 100644
index 0000000..9c81d1c
--- /dev/null
+++ b/azure-devops.html
@@ -0,0 +1,768 @@
+
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond</title>
+    <link rel="icon" href="data:image/svg+xml,&lt;svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22&gt;&lt;text y=%22.9em%22 font-size=%2290%22&gt;🚀&lt;/text&gt;&lt;/svg&gt;">
+
+    <!-- SEO & Metadata -->
+    <meta name="description" content="A comprehensive, opinionated cheatsheet for the entire Azure DevOps ecosystem. Covers Azure Boards, Repos, Pipelines, Test Plans, Artifacts, Terraform for IaC, and SonarQube for code quality.">
+    <meta name="keywords" content="DevOps, Azure DevOps, Cheatsheet, Azure Boards, Azure Repos, Azure Pipelines, Azure Test Plans, Azure Artifacts, Terraform, SonarQube, CI/CD, Agile, Git, IaC, Security, YAML">
+    <link rel="canonical" href="https://cheatsheets.davidveksler.com/azure-devops.html">
+
+    <!-- Open Graph / Facebook -->
+    <meta property="og:type" content="website">
+    <meta property="og:url" content="https://cheatsheets.davidveksler.com/azure-devops.html">
+    <meta property="og:title" content="The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond">
+    <meta property="og:description" content="A battle-hardened guide to the full Azure DevOps suite, including Boards for planning, Repos for code, Pipelines for CI/CD, Test Plans, and Artifacts for package management.">
+    <meta property="og:image" content="https://cheatsheets.davidveksler.com/images/azure-devops.png">
+    <meta property="og:image:alt" content="A visual diagram of the full DevOps lifecycle, highlighting components like Boards, Repos, and Pipelines.">
+
+    <!-- Twitter -->
+    <meta name="twitter:card" content="summary_large_image">
+    <meta name="twitter:url" content="https://cheatsheets.davidveksler.com/azure-devops.html">
+    <meta name="twitter:title" content="The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond">
+    <meta name="twitter:description" content="An opinionated cheatsheet for mastering the Azure DevOps ecosystem, from agile planning with Boards to CI/CD with Pipelines.">
+    <meta name="twitter:image" content="https://cheatsheets.davidveksler.com/images/azure-devops.png">
+    <meta name="twitter:creator" content="@heroiclife">
+
+    <!-- JSON-LD Structured Data -->
+    <script type="application/ld+json">
+    {
+      "@context": "https://schema.org",
+      "@type": "TechArticle",
+      "headline": "The Complete Azure DevOps Cheatsheet: From Boards to Pipelines & Beyond",
+      "description": "A comprehensive, opinionated cheatsheet for the entire Azure DevOps ecosystem. Covers Azure Boards, Repos, Pipelines, Test Plans, Artifacts, Terraform for IaC, and SonarQube for code quality.",
+      "image": "https://cheatsheets.davidveksler.com/images/azure-devops.png",
+      "author": {
+        "@type": "Person",
+        "name": "David Veksler (AI Generated)"
+      },
+      "publisher": {
+        "@type": "Organization",
+        "name": "David Veksler Cheatsheets",
+        "logo": {
+          "@type": "ImageObject",
+          "url": "https://cheatsheets.davidveksler.com/images/logo-placeholder.png"
+        }
+      },
+      "datePublished": "2024-06-15",
+      "dateModified": "2024-06-15",
+      "keywords": "DevOps, CI/CD, Azure DevOps, Azure Boards, Azure Repos, Azure Pipelines, Azure Test Plans, Azure Artifacts, Terraform, SonarQube, IaC, Git, Automation, Security"
+    }
+    </script>
+
+    <!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
+    <!-- Bootstrap Icons -->
+    <link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" rel="stylesheet">
+
+    <style>
+        :root {
+            --bs-body-bg: #1a1d21;
+            --bs-body-color: #e9ecef;
+            --bs-primary: #0d6efd; /* Azure Blue */
+            --card-bg: #212529;
+            --card-border-color: #495057;
+            --card-shadow-color: rgba(0, 0, 0, 0.4);
+            --text-color-main: #f8f9fa;
+            --text-color-secondary: #adb5bd;
+            --text-color-highlight: #78C1F3; /* Light Blue Highlight */
+            --schema-bg-color: rgba(33, 37, 41, 0.7);
+            --schema-border-color: #343a40;
+            --blueprint-grid-color: rgba(108, 117, 125, 0.1);
+
+            /* DevOps Category Colors */
+            --devops-color-plan: #2E7D32;      /* Planning Green */
+            --devops-color-scm: #F05032;       /* Git Orange */
+            --devops-color-ci: #F7B601;        /* SonarQube Yellow */
+            --devops-color-testing: #FF6F00;   /* Testing Amber */
+            --devops-color-artifacts: #6A1B9A; /* Artifacts Purple */
+            --devops-color-cd: #0078D4;        /* Azure Blue */
+            --devops-color-iac: #7B42BC;       /* Terraform Purple */
+            --devops-color-security: #D73A49;  /* Security Red */
+            --devops-color-monitoring: #28A745;/* Monitoring Green */
+
+            --db-category-color: var(--bs-primary); /* Default */
+        }
+
+        body {
+            background-color: var(--bs-body-bg);
+            background-image:
+                linear-gradient(var(--blueprint-grid-color) 1px, transparent 1px),
+                linear-gradient(to right, var(--blueprint-grid-color) 1px, transparent 1px);
+            background-size: 50px 50px;
+            font-family: 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
+        }
+
+        .page-header {
+            background: linear-gradient(135deg, rgba(13, 110, 253, 0.1), rgba(0, 0, 0, 0.2));
+            padding: 3rem 1.5rem;
+            text-align: center;
+            border-bottom: 1px solid var(--schema-border-color);
+            margin-bottom: 2rem;
+        }
+        .page-header h1 { font-weight: 300; font-size: 2.8rem; }
+        .page-header .lead { max-width: 800px; margin: auto; font-style: italic; color: var(--text-color-secondary); }
+
+        #filter-controls {
+            background-color: rgba(26, 29, 33, 0.85);
+            backdrop-filter: blur(8px);
+            padding: 1rem; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.3);
+            margin-bottom: 2rem; position: sticky; top: 10px; z-index: 1020;
+        }
+        #search-box {
+            background-color: #2c3136; border-color: var(--card-border-color); color: var(--bs-body-color);
+        }
+        #search-box::placeholder { color: #6c757d; }
+        #search-box:focus {
+            background-color: #2c3136; color: var(--bs-body-color); border-color: var(--bs-primary);
+            box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+        }
+
+        .schema-container {
+            background-color: var(--schema-bg-color); border: 1px solid var(--schema-border-color);
+            border-radius: 8px; padding: 1.5rem; margin-bottom: 2.5rem; box-shadow: 0 8px 30px rgba(0,0,0,0.2);
+        }
+
+        .section-title {
+            color: var(--db-category-color); margin: -2.7rem 0 1.5rem 0; font-weight: 600;
+            text-transform: uppercase; letter-spacing: .08em; font-size: 1.1rem; border-bottom: none;
+            padding: 0.4rem 1rem; background-color: var(--bs-body-bg); display: inline-block;
+            position: relative; left: 1rem;
+        }
+
+        .info-card {
+            background: var(--card-bg); border: 1px solid var(--card-border-color); border-radius: 6px;
+            box-shadow: 0 4px 12px var(--card-shadow-color); height: 100%; display: flex; flex-direction: column;
+            transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
+        }
+        .info-card:hover { transform: translateY(-5px); box-shadow: 0 8px 20px var(--card-shadow-color); }
+
+        .info-card h5 {
+            color: #fff; background-color: var(--db-category-color); font-size: 1rem; text-align: center;
+            margin: 0; padding: 0.7rem 0.5rem; font-weight: 600; display: flex; justify-content: center;
+            align-items: center; gap: .5rem; border-bottom: 1px solid var(--card-border-color);
+            border-radius: 5px 5px 0 0;
+        }
+        .info-card h5 .bi { font-size: 1.2em; opacity: 0.9; }
+
+        .card-content-wrapper { padding: 1rem; flex-grow: 1; display: flex; flex-direction: column; }
+        .info-card p.summary { font-size: .9rem; color: var(--text-color-secondary); margin-bottom: 1rem; flex-grow: 1; line-height: 1.6; }
+
+        .details-toggle {
+            font-size: 0.8rem; margin-top: auto; align-self: flex-start; color: var(--text-color-secondary);
+            border-color: var(--text-color-secondary); transition: all 0.2s ease;
+        }
+        .details-toggle:hover { color: #fff; background-color: var(--db-category-color); border-color: var(--db-category-color); }
+        .details-toggle .bi { transition: transform 0.2s ease-in-out; }
+        .details-toggle[aria-expanded="true"] .bi { transform: rotate(180deg); }
+
+        .collapse-content {
+            font-size: 0.9rem; border-top: 1px solid var(--card-border-color); padding: 1rem; background-color: #1a1d21;
+        }
+        .collapse-content h6 { font-weight: 700; color: var(--text-color-highlight); margin-top: 0.8rem; margin-bottom: 0.5rem; font-size: 0.95rem; }
+        .collapse-content ul { padding-left: 1.2rem; }
+        .collapse-content code {
+            font-size: 0.85rem; color: #e83e8c; background-color: rgba(255, 255, 255, 0.05);
+            padding: 0.2em 0.4em; border-radius: 3px;
+        }
+        .collapse-content .callout {
+            border-left: 4px solid var(--db-category-color); padding: 0.8rem 1rem; margin: 1rem 0;
+            background-color: rgba(255,255,255,0.03); border-radius: 0 4px 4px 0;
+        }
+
+        .term { font-weight: 600; color: var(--text-color-highlight); background-color: rgba(120, 193, 243, 0.1); padding: 0.1em 0.35em; border-radius: 3px; cursor: help; }
+
+        /* Category Color Styling */
+        .section-plan, .card-plan { --db-category-color: var(--devops-color-plan); }
+        .section-scm, .card-scm { --db-category-color: var(--devops-color-scm); }
+        .section-ci, .card-ci { --db-category-color: var(--devops-color-ci); }
+        .section-testing, .card-testing { --db-category-color: var(--devops-color-testing); }
+        .section-artifacts, .card-artifacts { --db-category-color: var(--devops-color-artifacts); }
+        .section-cd, .card-cd { --db-category-color: var(--devops-color-cd); }
+        .section-iac, .card-iac { --db-category-color: var(--devops-color-iac); }
+        .section-security, .card-security { --db-category-color: var(--devops-color-security); }
+        .section-monitoring, .card-monitoring { --db-category-color: var(--devops-color-monitoring); }
+
+        footer { border-top: 1px solid var(--schema-border-color); padding-top: 2rem; margin-top: 2rem; color: var(--text-color-secondary); font-size: 0.9em; }
+        footer a { color: var(--text-color-secondary); text-decoration: none; }
+        footer a:hover { color: #fff; text-decoration: underline; }
+    </style>
+</head>
+<body class="bg-dark text-light">
+
+    <header class="page-header">
+        <h1><i class="bi bi-bezier"></i> The Complete Azure DevOps Cheatsheet</h1>
+        <p class="lead">A brutally honest, battle-hardened guide to the entire Azure DevOps suite. From planning with Boards, coding with Repos, building and releasing with Pipelines, to testing, artifacts, and beyond.</p>
+    </header>
+
+    <div class="container">
+        <div id="filter-controls">
+            <input type="search" id="search-box" class="form-control mb-3" placeholder="Search topics, tools, or keywords (e.g., Boards, YAML, SAST)...">
+            <div id="category-filters" class="btn-toolbar" role="toolbar" aria-label="Category Filters"></div>
+            <div class="alert alert-warning mt-3" id="no-results" style="display: none;">No items match your criteria.</div>
+        </div>
+    </div>
+
+    <main class="container" id="main-container">
+
+        <!-- 1. Agile Planning (Azure Boards) -->
+        <div class="schema-container section-plan" data-section-id="section-plan" data-section-name="Plan">
+            <h2 class="section-title">Agile Planning & Work Management</h2>
+            <div class="row g-4">
+                <div class="col-lg-6">
+                    <div class="info-card card-plan" id="card-plan-boards">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-kanban"></i> Azure Boards</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">If you don't plan your work, you plan to fail. Azure Boards is the central hub for work item tracking, backlogs, and sprint planning. It's where all work should originate.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePlanBoards" aria-expanded="false" aria-controls="collapsePlanBoards">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapsePlanBoards">
+                                <h6>Core Components:</h6>
+                                <ul>
+                                    <li><strong>Work Items:</strong> The fundamental units of work (e.g., User Story, Bug, Task).</li>
+                                    <li><strong>Backlogs:</strong> A prioritized list of work items. You'll have product backlogs (all work) and sprint backlogs (work for the current iteration).</li>
+                                    <li><strong>Boards:</strong> Kanban-style visualization of your workflow. Customize columns to match your team's process.</li>
+                                    <li><strong>Sprints/Iterations:</strong> Time-boxed periods where a team commits to a set of work.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-plan" id="card-plan-linking">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-link-45deg"></i> Best Practice: Traceability</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Your mantra: "If it's not in Boards, it doesn't exist." Every commit, branch, and pull request must be linked to a work item. This provides end-to-end traceability from idea to deployment.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapsePlanLinking" aria-expanded="false" aria-controls="collapsePlanLinking">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapsePlanLinking">
+                                <h6>Why It's Non-Negotiable:</h6>
+                                <ul>
+                                    <li><strong>Context:</strong> Understand *why* a change was made, directly from the code.</li>
+                                    <li><strong>Auditing:</strong> Easily track all changes related to a specific feature or bug fix.</li>
+                                    <li><strong>Automation:</strong> Use branch policies to enforce work item linking on all pull requests.</li>
+                                    <li><strong>Reporting:</strong> Generate accurate reports on team velocity, cycle time, and project status.</li>
+                                </ul>
+                                <div class="callout callout-danger"><strong>Critical Rule:</strong> Configure your `main` branch policy to "Check for linked work items." This is the simplest and most effective process improvement you can make.</div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 2. Source Control Management (SCM) -->
+        <div class="schema-container section-scm" data-section-id="section-scm" data-section-name="Code">
+            <h2 class="section-title">Source Control Management</h2>
+            <div class="row g-4">
+                <div class="col-lg-6">
+                    <div class="info-card card-scm" id="card-scm-azure-repos">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-git"></i> Azure Repos</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">The foundation of your pipeline. It's Git. Don't overthink it. If your code is in TFVC, your top priority is migrating. No excuses.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseScmAzureRepos" aria-expanded="false" aria-controls="collapseScmAzureRepos">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseScmAzureRepos">
+                                <h6>Core Principle:</h6>
+                                <p>This is your single source of truth. All changes—code, configuration, pipelines, infrastructure—must live here. Protect it accordingly.</p>
+                                <h6>Tooling:</h6>
+                                <ul>
+                                    <li><strong>Azure Repos:</strong> It's a perfectly functional Git host that integrates tightly with the rest of Azure DevOps.</li>
+                                    <li><strong>Git:</strong> The undisputed standard for version control. Anything else is a historical artifact and technical debt.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-scm" id="card-scm-branch-policies">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-sign-turn-right"></i> Best Practice: Branch Policies</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Policies are non-negotiable. Protect your `main` branch like it's the last bastion of sanity. Automate your Pull Requests to enforce quality gates from the very start.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseScmBranchPolicies" aria-expanded="false" aria-controls="collapseScmBranchPolicies">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseScmBranchPolicies">
+                                <h6>Mandatory Policies for `main`:</h6>
+                                <ul>
+                                    <li><strong>Require a minimum number of reviewers:</strong> No developer merges their own code without a second pair of eyes.</li>
+                                    <li><strong>Check for linked work items:</strong> Every change must be traceable to a requirement or bug.</li>
+                                    <li><strong>Check for comment resolution:</strong> Ensure all review feedback is addressed.</li>
+                                    <li><strong>Enforce Build Validation:</strong> Link your CI pipeline here. If the PR doesn't build and pass tests, it's blocked. This is your first quality gate.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 3. Continuous Integration (CI) -->
+        <div class="schema-container section-ci" data-section-id="section-ci" data-section-name="Build">
+            <h2 class="section-title">Continuous Integration</h2>
+            <div class="row g-4">
+                <div class="col-lg-4">
+                    <div class="info-card card-ci" id="card-ci-pipelines">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-filetype-yml"></i> Azure Pipelines (YAML ONLY)</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Your pipeline is code. Treat it like code. Do NOT use the "classic" UI editor. It creates a click-ops nightmare that is impossible to version, review, or scale.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiPipelines" aria-expanded="false" aria-controls="collapseCiPipelines">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseCiPipelines">
+                                <h6>Core Principle:</h6>
+                                <p>Define your build pipeline as an `azure-pipelines.yml` file, committed to the root of your repository. This ensures your pipeline is versioned alongside your code.</p>
+                                <h6>Best Practices:</h6>
+                                <ul>
+                                    <li><strong>Use Templates:</strong> For common, reusable steps, create pipeline templates. This standardizes your process and makes maintenance trivial.</li>
+                                    <li><strong>Use Variable Groups:</strong> For shared variables and secrets. Link them to Azure Key Vault.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-4">
+                    <div class="info-card card-ci" id="card-ci-sonarqube">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-search-heart"></i> SonarQube Integration</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary"><span class="term" data-bs-toggle="tooltip" title="A tool for continuous inspection of code quality.">SonarQube</span> is your automated code reviewer. Integrate it into CI and fail the build if the quality gate is not met.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiSonarqube" aria-expanded="false" aria-controls="collapseCiSonarqube">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseCiSonarqube">
+                                <h6>Typical CI Pipeline Steps with SonarQube:</h6>
+                                <ol>
+                                    <li><strong>Prepare Analysis:</strong> Connects to your SonarQube server.</li>
+                                    <li><strong>Run Build & Tests:</strong> Compile code and generate code coverage reports.</li>
+                                    <li><strong>Run Code Analysis:</strong> Sonar scanner analyzes code and coverage reports.</li>
+                                    <li><strong>Publish Quality Gate Result:</strong> Polls SonarQube and checks the Quality Gate status.</li>
+                                </ol>
+                                <div class="callout callout-danger">
+                                    <strong>Critical Rule:</strong> Configure the "Publish Quality Gate Result" task to fail the build if the gate fails.
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-4">
+                    <div class="info-card card-ci" id="card-ci-stages">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-boxes"></i> CI Key Stages</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">The moment code is merged, it must be built, tested, and packaged. The goal is to catch errors early and often, before they reach production.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCiStages" aria-expanded="false" aria-controls="collapseCiStages">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseCiStages">
+                                <h6>Mandatory Stages:</h6>
+                                <ul>
+                                    <li><strong>Build:</strong> Compile the code. If it doesn't build, it's broken.</li>
+                                    <li><strong>Test:</strong> Run unit and integration tests.</li>
+                                    <li><strong>Scan:</strong> Perform security and quality scans (e.g., SonarQube, SAST, SCA).</li>
+                                    <li><strong>Package:</strong> Create a deployable artifact (e.g., a <span class="term" data-bs-toggle="tooltip" title="A standardized unit of software that packages up code and all its dependencies.">Docker image</span>).</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 4. Quality Assurance (Azure Test Plans) -->
+        <div class="schema-container section-testing" data-section-id="section-testing" data-section-name="Test">
+            <h2 class="section-title">Quality Assurance & Test Management</h2>
+            <div class="row g-4">
+                <div class="col-lg-6">
+                    <div class="info-card card-testing" id="card-test-plans">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-clipboard2-check"></i> Azure Test Plans</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Automated tests are essential but don't cover everything. Use Azure Test Plans for manual, exploratory, and user acceptance testing (UAT) to ensure comprehensive quality.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTestPlans" aria-expanded="false" aria-controls="collapseTestPlans">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseTestPlans">
+                                <h6>Key Features:</h6>
+                                <ul>
+                                    <li><strong>Test Plans & Suites:</strong> Group test cases into logical suites. Requirement-based suites automatically link test cases to user stories in Boards.</li>
+                                    <li><strong>Test Case Management:</strong> Define detailed, step-by-step manual test cases with expected results.</li>
+                                    <li><strong>Web-based Test Runner:</strong> Execute tests directly in the browser, marking steps as pass/fail and capturing screenshots or recordings.</li>
+                                    <li><strong>Exploratory Testing:</strong> Capture rich data (notes, screenshots, HAR files) during unscripted testing sessions.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-testing" id="card-test-integration">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-arrows-angle-contract"></i> End-to-End Traceability</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Linking test results back to requirements is critical for quality reporting. Test Plans creates a full audit trail, showing which tests validate which features and what their latest outcomes are.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTestIntegration" aria-expanded="false" aria-controls="collapseTestIntegration">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseTestIntegration">
+                                <h6>How It Connects:</h6>
+                                <ul>
+                                    <li>Failing a manual test step can automatically create a bug in Azure Boards, pre-populated with repro steps and system info.</li>
+                                    <li>Test results from automated CI/CD pipeline runs can be published to Test Plans, providing a single view of both manual and automated test quality.</li>
+                                    <li>Stakeholders can view the "Test" tab on a work item to see all associated test cases and their results, providing confidence before deployment.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 5. Package Management (Azure Artifacts) -->
+        <div class="schema-container section-artifacts" data-section-id="section-artifacts" data-section-name="Artifacts">
+            <h2 class="section-title">Package Management</h2>
+            <div class="row g-4">
+                <div class="col-lg-6">
+                    <div class="info-card card-artifacts" id="card-artifacts-overview">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-box-seam"></i> Azure Artifacts</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Manage your dependencies. Azure Artifacts provides private, secure feeds for hosting packages like NuGet, npm, Maven, Python, and Universal Packages. Stop relying solely on public registries.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArtifactsOverview" aria-expanded="false" aria-controls="collapseArtifactsOverview">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseArtifactsOverview">
+                                <h6>Why Use It?</h6>
+                                <ul>
+                                    <li><strong>Reliability:</strong> Cache upstream packages. If a public registry goes down or a package is unpublished, your builds won't break.</li>
+                                    <li><strong>Security:</strong> Control what packages your organization uses. Share private packages securely across teams.</li>
+                                    <li><strong>Integration:</strong> Seamlessly integrated with Azure Pipelines for publishing and restoring packages.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-artifacts" id="card-artifacts-feeds">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-diagram-3"></i> Feeds and Views</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Don't just dump packages into a single feed. Use views (`@local`, `@prerelease`, `@release`) to promote packages through different quality rings, just like you do with your code.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArtifactsFeeds" aria-expanded="false" aria-controls="collapseArtifactsFeeds">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseArtifactsFeeds">
+                                <h6>Release Flow with Views:</h6>
+                                <ol>
+                                    <li>CI build publishes a new package version to the `@local` view.</li>
+                                    <li>Automated tests run against the `@local` view.</li>
+                                    <li>If tests pass, the pipeline promotes the package to the `@prerelease` view for broader integration testing.</li>
+                                    <li>After validation, a release pipeline promotes the package to the `@release` view, making it available for production use.</li>
+                                </ol>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 6. Infrastructure as Code (IaC) -->
+        <div class="schema-container section-iac" data-section-id="section-iac" data-section-name="IaC">
+            <h2 class="section-title">Infrastructure as Code</h2>
+            <div class="row g-4">
+                <div class="col-lg-6">
+                    <div class="info-card card-iac" id="card-iac-terraform">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-filetype-tf"></i> Terraform</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Your infrastructure must be defined as code. Manual configuration in the Azure Portal is a recipe for disaster. <span class="term" data-bs-toggle="tooltip" title="An open-source IaC tool by HashiCorp.">Terraform</span> is the industry standard.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseIacTerraform" aria-expanded="false" aria-controls="collapseIacTerraform">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseIacTerraform">
+                                <h6>Why Terraform?</h6>
+                                <p>While Microsoft pushes Bicep/ARM, Terraform is cloud-agnostic and its `plan` command is a lifesaver for preventing accidental changes.</p>
+                                <h6>The Holy Trinity of Terraform Commands in a Pipeline:</h6>
+                                <ul>
+                                    <li><code>terraform init</code>: Initializes the backend and providers.</li>
+                                    <li><code>terraform plan</code>: Shows exactly what will change. This step must create a plan artifact that requires manual approval.</li>
+                                    <li><code>terraform apply</code>: Executes the approved plan.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-iac" id="card-iac-state">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-database-lock"></i> Terraform Remote State</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">The biggest mistake teams make with Terraform is storing the `terraform.tfstate` file locally. Always use a remote backend like an Azure Storage Account.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseIacState" aria-expanded="false" aria-controls="collapseIacState">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseIacState">
+                                <h6>Why Remote State is Critical:</h6>
+                                <ul>
+                                    <li><strong>Collaboration:</strong> Allows multiple team members to work on the same infrastructure.</li>
+                                    <li><strong>State Locking:</strong> Prevents concurrent runs from corrupting the state file.</li>
+                                    <li><strong>Security:</strong> The state file can contain secrets. Storing it in a secured storage account is essential.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 7. Continuous Delivery/Deployment (CD) -->
+        <div class="schema-container section-cd" data-section-id="section-cd" data-section-name="Release">
+            <h2 class="section-title">Continuous Delivery/Deployment</h2>
+            <div class="row g-4">
+                 <div class="col-lg-6">
+                    <div class="info-card card-cd" id="card-cd-releases">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-rocket-takeoff"></i> Azure Pipelines (Releases)</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Automating your release is the whole point. Release Pipelines offer better visualization of your environments and crucial manual approval gates for production.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCdReleases" aria-expanded="false" aria-controls="collapseCdReleases">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseCdReleases">
+                                <h6>Release Pipeline Structure:</h6>
+                                <ul>
+                                    <li><strong>Artifacts:</strong> Triggered by a new build artifact (e.g., Docker image, Terraform plan).</li>
+                                    <li><strong>Stages:</strong> Create a stage for each environment (e.g., Dev, QA, Prod).</li>
+                                    <li><strong>Approval Gates:</strong> Use automated gates (smoke tests) and manual gates (human approval) to control promotion between stages.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-cd" id="card-cd-concepts">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-lightbulb"></i> Key Deployment Concepts</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Differentiate between Continuous Delivery (manual deploy to prod) and Continuous Deployment (automatic to prod). Use deployment strategies to limit blast radius.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCdConcepts" aria-expanded="false" aria-controls="collapseCdConcepts">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseCdConcepts">
+                                <ul>
+                                    <li><strong>Immutable Infrastructure:</strong> Don't modify running servers. Replace them with fresh ones built from your artifacts.</li>
+                                    <li><strong>Blue/Green or Canary Deployments:</strong> Deploy to a subset of users (Canary) or a parallel environment (Blue/Green) before a full rollout.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 8. Security -->
+        <div class="schema-container section-security" data-section-id="section-security" data-section-name="Security">
+            <h2 class="section-title">Security</h2>
+            <div class="row g-4">
+                 <div class="col-lg-6">
+                    <div class="info-card card-security" id="card-security-practices">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-shield-check"></i> Key Security Practices (Shift Left)</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Security is not a separate step; it's a part of every step. Embed automated security checks into your pipeline to catch vulnerabilities early.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityPractices" aria-expanded="false" aria-controls="collapseSecurityPractices">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseSecurityPractices">
+                                <h6>Pipeline Integration Points:</h6>
+                                <ul>
+                                    <li><strong><span class="term" data-bs-toggle="tooltip" title="Static Application Security Testing">SAST</span>:</strong> Analyze source code. SonarQube has SAST capabilities.</li>
+                                    <li><strong><span class="term" data-bs-toggle="tooltip" title="Software Composition Analysis">SCA</span>:</strong> Scan open-source dependencies for known vulnerabilities.</li>
+                                    <li><strong>Container Scanning:</strong> Scan your Docker images for vulnerabilities.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-security" id="card-security-keyvault">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-key"></i> Secret Management: Azure Key Vault</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Don't put secrets in your code, variable groups, or YAML files. This is amateur hour. Use Azure Key Vault.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityKeyvault" aria-expanded="false" aria-controls="collapseSecurityKeyvault">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseSecurityKeyvault">
+                                <h6>The Only Acceptable Way:</h6>
+                                <p>Store all secrets in Azure Key Vault. In your Pipeline, use a Variable Group linked to the Key Vault. Secrets will be fetched at runtime and masked in logs.</p>
+                                <div class="callout callout-danger">
+                                    <strong>Critical Rule:</strong> Developers should not have direct access to production secrets. The pipeline is the only entity that should fetch and use them in production.
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 9. Monitoring & Observability -->
+        <div class="schema-container section-monitoring" data-section-id="section-monitoring" data-section-name="Monitor">
+            <h2 class="section-title">Monitoring & Observability</h2>
+            <div class="row g-4">
+                 <div class="col-lg-6">
+                    <div class="info-card card-monitoring" id="card-monitoring-pillars">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-kanban"></i> The Three Pillars</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">If you're not monitoring your application in production, you're flying blind. Observability is understanding your system's state from the outside.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseMonitoringPillars" aria-expanded="false" aria-controls="collapseMonitoringPillars">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseMonitoringPillars">
+                                <ul>
+                                    <li><strong>Logging:</strong> Records of discrete events. Use structured logging.</li>
+                                    <li><strong>Metrics:</strong> Aggregated, time-series data on key performance indicators (e.g., CPU, latency).</li>
+                                    <li><strong>Tracing:</strong> Track a single request as it moves through your distributed system.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-lg-6">
+                    <div class="info-card card-monitoring" id="card-monitoring-tools">
+                        <div class="card-body d-flex flex-column">
+                            <h5><i class="bi bi-tools"></i> Azure Tooling</h5>
+                            <div class="card-content-wrapper">
+                                <p class="summary">Use the integrated Azure tools. They're not always best-in-class, but their deep integration simplifies your life immensely.</p>
+                                <button class="btn btn-outline-secondary btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseMonitoringTools" aria-expanded="false" aria-controls="collapseMonitoringTools">Details <i class="bi bi-chevron-down"></i></button>
+                            </div>
+                            <div class="collapse collapse-content" id="collapseMonitoringTools">
+                                <h6>Recommended Azure Stack:</h6>
+                                <ul>
+                                    <li><strong>Azure Monitor:</strong> The umbrella service for metrics and basic logging.</li>
+                                    <li><strong>Application Insights:</strong> The APM solution. Instrument your code with its SDK to get rich logging, dependency tracking, and distributed tracing.</li>
+                                    <li><strong>Log Analytics Workspace:</strong> The destination for all your logs. Use Kusto Query Language (KQL) to query everything.</li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+    </main>
+
+    <footer class="container text-center py-4">
+        <p class="mb-1">© <span id="currentYear"></span> David Veksler Cheatsheets</p>
+        <p class="mb-2" style="font-size: 0.8em;">Last Updated: <span id="lastUpdatedDate">June 15, 2024</span></p>
+        <div>
+            <a href="https://learn.microsoft.com/en-us/azure/devops/" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-box"></i> Azure DevOps Docs</a>
+            <a href="https://www.terraform.io/docs" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-file-earmark-code"></i> Terraform Docs</a>
+            <a href="https://docs.sonarqube.org/latest/" target="_blank" rel="noopener noreferrer" class="mx-2"><i class="bi bi-search"></i> SonarQube Docs</a>
+        </div>
+    </footer>
+
+    <!-- Bootstrap JS -->
+    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
+
+    <script>
+        document.addEventListener('DOMContentLoaded', () => {
+            // Initialize Bootstrap Tooltips
+            const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
+            tooltipTriggerList.map(function (tooltipTriggerEl) {
+                return new bootstrap.Tooltip(tooltipTriggerEl);
+            });
+
+            document.getElementById('currentYear').textContent = new Date().getFullYear();
+
+            const searchBox = document.getElementById('search-box');
+            const categoryFiltersContainer = document.getElementById('category-filters');
+            const noResultsDiv = document.getElementById('no-results');
+            const allSchemaContainers = Array.from(document.querySelectorAll('.schema-container'));
+            let activeFilter = 'all';
+
+            function initializeFilters() {
+                const allButton = document.createElement('button');
+                allButton.type = 'button';
+                allButton.className = 'btn btn-primary filter-btn active';
+                allButton.textContent = 'All';
+                allButton.dataset.filter = 'all';
+                categoryFiltersContainer.appendChild(allButton);
+
+                const btnGroup = document.createElement('div');
+                btnGroup.className = 'btn-group flex-wrap ms-2';
+                btnGroup.setAttribute('role', 'group');
+
+                const sectionColors = {};
+                allSchemaContainers.forEach(section => {
+                    const sectionId = section.dataset.sectionId;
+                    const sectionName = section.dataset.sectionName || 'Unnamed';
+                    const computedColor = getComputedStyle(section).getPropertyValue('--db-category-color').trim();
+                    sectionColors[sectionId] = computedColor;
+
+                    const button = document.createElement('button');
+                    button.type = 'button';
+                    button.className = 'btn btn-outline-secondary filter-btn';
+                    button.textContent = sectionName;
+                    button.dataset.filter = sectionId;
+                    button.style.setProperty('--bs-btn-border-color', computedColor);
+                    button.style.setProperty('--bs-btn-hover-border-color', computedColor);
+                    button.style.setProperty('--bs-btn-color', computedColor);
+                    button.style.setProperty('--bs-btn-hover-color', '#fff');
+                    button.style.setProperty('--bs-btn-hover-bg', computedColor);
+                    button.style.setProperty('--bs-btn-active-bg', computedColor);
+                    button.style.setProperty('--bs-btn-active-border-color', computedColor);
+                    btnGroup.appendChild(button);
+                });
+                categoryFiltersContainer.appendChild(btnGroup);
+
+                categoryFiltersContainer.addEventListener('click', (event) => {
+                    if (event.target.classList.contains('filter-btn')) {
+                        document.querySelectorAll('#category-filters .filter-btn.active').forEach(btn => btn.classList.remove('active'));
+                        event.target.classList.add('active');
+                        activeFilter = event.target.dataset.filter;
+                        applyFiltersAndSearch();
+                    }
+                });
+                searchBox.addEventListener('input', applyFiltersAndSearch);
+            }
+
+            function applyFiltersAndSearch() {
+                const searchTerm = searchBox.value.toLowerCase().trim();
+                let itemsFound = 0;
+
+                allSchemaContainers.forEach(section => {
+                    const sectionId = section.dataset.sectionId;
+                    let sectionHasVisibleCards = false;
+                    const cardsInSection = Array.from(section.querySelectorAll('.info-card'));
+
+                    cardsInSection.forEach(card => {
+                        const cardTextContent = card.textContent.toLowerCase();
+                        const matchesSearch = searchTerm === '' || cardTextContent.includes(searchTerm);
+                        const matchesFilter = activeFilter === 'all' || sectionId === activeFilter;
+
+                        const cardColumn = card.closest('.col-lg-4, .col-lg-6');
+                        if (matchesSearch && matchesFilter) {
+                            if(cardColumn) cardColumn.style.display = '';
+                            sectionHasVisibleCards = true;
+                            itemsFound++;
+                        } else {
+                             if(cardColumn) cardColumn.style.display = 'none';
+                        }
+                    });
+
+                    section.style.display = sectionHasVisibleCards ? '' : 'none';
+                });
+                noResultsDiv.style.display = itemsFound === 0 ? 'block' : 'none';
+            }
+
+            const collapseElements = document.querySelectorAll('.collapse');
+            collapseElements.forEach(collapseEl => {
+                const button = document.querySelector(`.details-toggle[data-bs-target="#${collapseEl.id}"]`);
+                if(button) {
+                    const iconEl = button.querySelector('.bi');
+                    collapseEl.addEventListener('show.bs.collapse', () => iconEl.classList.replace('bi-chevron-down', 'bi-chevron-up'));
+                    collapseEl.addEventListener('hide.bs.collapse', () => iconEl.classList.replace('bi-chevron-up', 'bi-chevron-down'));
+                }
+            });
+
+            initializeFilters();
+        });
+    </script>
+</body>
+</html>