{
  "$schema": "https://schema.management.azure.com/schemas/2021-09-09/uiFormDefinition.schema.json#",
  "view": {
    "kind": "Form",
    "properties": {
      "title": "Install General Validation v0.5.0",
      "steps": [
        {
          "name": "basics",
          "label": "Basics",
          "elements": [
            {
              "name": "scope",
              "type": "Microsoft.Common.ResourceScope",
              "resourceGroup": {
                "allowExisting": false
              },
              "location": {
                "label": "Deployment location",
                "toolTip": "Central US is the only region live-qualified for the v0.5.0 installer. Additional regions will be added only after the same deployment qualification.",
                "resourceTypes": [ "Microsoft.App/containerApps" ],
                "allowedValues": [ "centralus" ]
              }
            },
            {
              "name": "deploymentInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Warning",
                "text": "Fresh installation only: create the new, dedicated General Validation resource group requested below. The portal prevents selecting an existing group so uninstall cannot accidentally delete unrelated resources. This v0.5.0 installer does not update an existing installation; do not reuse its resource group. Validation compute, customer data, result tables, and evidence artifacts remain in your Azure tenant."
              }
            },
            {
              "name": "rightsInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Info",
                "text": "The standard install requires Owner, or Contributor plus Role Based Access Control Administrator (or User Access Administrator), on the subscription. Contributor alone cannot create the managed-identity role assignments. If you choose subscription-wide Data Factory discovery below, the custom role also requires Owner, or Contributor plus User Access Administrator. Entra app-registration permissions are separate from Azure subscription roles."
              }
            },
            {
              "name": "networkInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Warning",
                "text": "Network posture: this standard installer does not create or attach a VNet. The application, PostgreSQL, results-ADLS, and Log Analytics use Azure public endpoints. PostgreSQL accepts network connections from Azure services but uses Entra-only authentication with no database password. Storage disables anonymous and shared-key access; callers must use Entra and RBAC. This installer does not create an ingress WAF/gateway, restrict application egress, or add private connectivity to customer systems. Customers requiring private endpoints or customer-managed networking need a separately engineered deployment."
              }
            },
            {
              "name": "namePrefix",
              "type": "Microsoft.Common.TextBox",
              "label": "Resource name prefix",
              "defaultValue": "gv",
              "toolTip": "Short prefix for provisioned resource names.",
              "constraints": {
                "required": true,
                "regex": "^[a-z][a-z0-9]{1,10}$",
                "validationMessage": "2-11 chars, lowercase letters/digits, start with a letter."
              }
            },
            {
              "name": "tagsByResource",
              "type": "Microsoft.Common.TagsByResource",
              "resources": [
                "Microsoft.Resources/resourceGroups"
              ]
            },
            {
              "name": "factoryDiscovery",
              "type": "Microsoft.Common.OptionsGroup",
              "label": "Data Factory discovery access",
              "defaultValue": "Grant per factory after install (recommended)",
              "toolTip": "The recommended option grants no subscription-wide factory role at install. Grant the built-in Reader role only on each selected source factory. The broad option creates a subscription-scoped custom role carrying only Data Factory metadata-read actions so every current and future factory is browse-ready.",
              "constraints": {
                "required": true,
                "allowedValues": [
                  { "label": "Grant per factory after install (recommended)", "value": "manual" },
                  { "label": "Read all Data Factories in this subscription", "value": "subscription" }
                ]
              }
            },
            {
              "name": "storageDiscovery",
              "type": "Microsoft.Common.OptionsGroup",
              "label": "Execution data access",
              "defaultValue": "Grant access only to selected storage accounts (recommended)",
              "toolTip": "The execution Data Factory must read source and target data to validate it. The recommended option grants nothing subscription-wide at install: when a dataset needs access, an Azure administrator uses the customer-owned portal workflow to review and grant Storage Blob Data Reader on only that storage account. The broad option grants read access to every current and future Blob / ADLS Gen2 account in this subscription.",
              "constraints": {
                "required": true,
                "allowedValues": [
                  { "label": "Grant access only to selected storage accounts (recommended)", "value": "manual" },
                  { "label": "Read all storage data in this subscription (broad access)", "value": "subscription" }
                ]
              }
            }
          ]
        },
        {
          "name": "reliability",
          "label": "Reliability",
          "elements": [
            {
              "name": "reliabilityInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Info",
                "text": "These affect data recoverability, in-region database availability, and cost. Geo-redundant backup is CREATE-TIME ONLY — it cannot be enabled after deployment. General Validation stores metadata (config, run status, result pointers) in PostgreSQL; validation result and evidence Delta tables live in the ADLS Gen2 account this deploy creates. The application and compute remain single-region and do not fail over automatically."
              }
            },
            {
              "name": "drPosture",
              "type": "Microsoft.Common.OptionsGroup",
              "label": "Data-recovery posture",
              "defaultValue": "Regional recovery (recommended)",
              "toolTip": "Regional recovery replicates database backups and result storage to the Azure paired region for restoration after a regional failure. It does not provide automatic application failover. Single region keeps database backups and result storage in one region for strict data-residency requirements.",
              "constraints": {
                "required": true,
                "allowedValues": [
                  { "label": "Regional recovery (recommended)", "value": "geo" },
                  { "label": "Single region (data-residency)", "value": "local" }
                ]
              }
            },
            {
              "name": "dbTier",
              "type": "Microsoft.Common.OptionsGroup",
              "label": "Database tier",
              "defaultValue": "General Purpose + zone-redundant HA (recommended)",
              "toolTip": "General Purpose with zone-redundant HA is the production default and runs a hot standby in another availability zone. Burstable (Standard_B1ms) is lower cost but has no standby or in-region database failover.",
              "constraints": {
                "required": true,
                "allowedValues": [
                  { "label": "General Purpose + zone-redundant HA (recommended)", "value": "ha" },
                  { "label": "Burstable — low cost, no HA", "value": "burstable" }
                ]
              }
            }
          ]
        },
        {
          "name": "image",
          "label": "Product access",
          "elements": [
            {
              "name": "registryInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Info",
                "text": "Enter the per-recipient pull token the publisher issued you. The registry and digest-pinned image are fixed by this versioned installer. Azure Container Apps stores the pull password as a secret on both app resources and uses it only to pull the image; it is not injected into the application containers."
              }
            },
            {
              "name": "registryUsername",
              "type": "Microsoft.Common.TextBox",
              "label": "Pull token name",
              "toolTip": "The per-recipient, repository-scoped pull-token NAME the publisher issued you.",
              "constraints": { "required": true }
            },
            {
              "name": "registryPassword",
              "type": "Microsoft.Common.PasswordBox",
              "label": { "password": "Pull token password", "confirmPassword": "Confirm token password" },
              "toolTip": "The password for the pull token. Stored as a Container App secret and used by Azure Container Apps to pull the image; it is not injected into the application container.",
              "constraints": { "required": true },
              "options": { "hideConfirmation": true }
            }
          ]
        },
        {
          "name": "secrets",
          "label": "First-time setup",
          "elements": [
            {
              "name": "bootstrapInfo",
              "type": "Microsoft.Common.InfoBox",
              "options": {
                "style": "Warning",
                "text": "Save this secret until first-time setup is complete. Azure stores it only on the API Container App as a secret protected by Azure RBAC; it is not supplied to the worker or migration container, and General Validation does not display it after deployment. When deployment finishes, open the setupUrl output and enter this value to configure login and claim the owner account. Generate a UUID locally with uuidgen or PowerShell: [guid]::NewGuid().ToString()."
              }
            },
            {
              "name": "bootstrapSecret",
              "type": "Microsoft.Common.PasswordBox",
              "label": { "password": "Bootstrap secret", "confirmPassword": "Confirm secret" },
              "toolTip": "Secret gating /auth/setup before the first owner exists. Paste a random 16+ char string (a UUID is ideal). It is required for each deployment; save the install value through post-deploy setup, and use your approved secret-handling process for later updates.",
              "constraints": {
                "required": true,
                "regex": "^[A-Za-z0-9._-]{16,256}$",
                "validationMessage": "16-256 chars: letters, digits, . _ -"
              },
              "options": { "hideConfirmation": true }
            }
          ]
        }
      ]
    },
    "outputs": {
      "kind": "Subscription",
      "subscriptionId": "[steps('basics').scope.subscription.subscriptionId]",
      "location": "[steps('basics').scope.location.name]",
      "parameters": {
        "location": "[steps('basics').scope.location.name]",
        "resourceGroupName": "[steps('basics').scope.resourceGroup.name]",
        "namePrefix": "[steps('basics').namePrefix]",
        "tagsByResource": "[steps('basics').tagsByResource]",
        "grantSubscriptionFactoryRead": "[equals(steps('basics').factoryDiscovery, 'subscription')]",
        "grantSubscriptionStorageRead": "[equals(steps('basics').storageDiscovery, 'subscription')]",
        "enableGeoRedundancy": "[equals(steps('reliability').drPosture, 'geo')]",
        "enableDatabaseHighAvailability": "[equals(steps('reliability').dbTier, 'ha')]",
        "registryUsername": "[steps('image').registryUsername]",
        "registryPassword": "[steps('image').registryPassword]",
        "bootstrapSecret": "[steps('secrets').bootstrapSecret]"
      }
    }
  }
}
