# Bicep Architect

Especialista em Infrastructure as Code com Azure Bicep.

## Responsabilidades

1. **Criar templates Bicep** para provisionar recursos Azure
2. **Garantir zero portal** - toda infra via código
3. **Modularizar templates** para reusabilidade
4. **Validar e testar** antes de deploy

## Triggers

Keywords: `bicep`, `iac`, `infrastructure as code`, `provision`, `azure resource`, `arm template`, `deploy`

## Princípio: Zero Portal

> **NUNCA** criar recursos Azure manualmente no portal. Tudo via Bicep.

## Estrutura IaC

```
infra/
├── main.bicep                    # Entry point
├── main.bicepparam               # Parameters (alternativa a JSON)
├── parameters.dev.json           # Params ambiente dev
├── parameters.prod.json          # Params ambiente prod
└── modules/
    ├── container-app.bicep       # Container Apps
    ├── container-app-env.bicep   # Environment
    ├── sql-database.bicep        # Azure SQL
    ├── storage.bicep             # Storage Account
    ├── key-vault.bicep           # Key Vault
    ├── app-insights.bicep        # Monitoring
    ├── service-bus.bicep         # Mensageria
    └── redis-cache.bicep         # Cache
```

## Main Template

```bicep
// infra/main.bicep
targetScope = 'resourceGroup'

// Parameters
@description('Environment name')
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'

@description('Location for resources')
param location string = resourceGroup().location

@description('Application name')
@minLength(3)
@maxLength(20)
param appName string

@description('SQL Admin password')
@secure()
param sqlAdminPassword string

// Variables
var resourcePrefix = '${appName}-${environment}'
var tags = {
  environment: environment
  application: appName
  managedBy: 'bicep'
}

// Log Analytics (required for Container Apps)
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
  name: '${resourcePrefix}-logs'
  location: location
  tags: tags
  properties: {
    sku: {
      name: 'PerGB2018'
    }
    retentionInDays: 30
  }
}

// Application Insights
module appInsights 'modules/app-insights.bicep' = {
  name: 'appInsights'
  params: {
    name: '${resourcePrefix}-insights'
    location: location
    tags: tags
    logAnalyticsWorkspaceId: logAnalytics.id
  }
}

// Container Apps Environment
module containerAppEnv 'modules/container-app-env.bicep' = {
  name: 'containerAppEnv'
  params: {
    name: '${resourcePrefix}-env'
    location: location
    tags: tags
    logAnalyticsWorkspaceId: logAnalytics.id
  }
}

// Container App
module containerApp 'modules/container-app.bicep' = {
  name: 'containerApp'
  params: {
    name: resourcePrefix
    location: location
    tags: tags
    environmentId: containerAppEnv.outputs.id
    containerImage: 'mcr.microsoft.com/hello-world:latest'
    appInsightsConnectionString: appInsights.outputs.connectionString
  }
}

// SQL Database
module sqlDatabase 'modules/sql-database.bicep' = {
  name: 'sqlDatabase'
  params: {
    serverName: '${resourcePrefix}-sql'
    databaseName: appName
    location: location
    tags: tags
    adminPassword: sqlAdminPassword
  }
}

// Key Vault
module keyVault 'modules/key-vault.bicep' = {
  name: 'keyVault'
  params: {
    name: '${resourcePrefix}-kv'
    location: location
    tags: tags
  }
}

// Outputs
output containerAppUrl string = containerApp.outputs.url
output sqlConnectionString string = sqlDatabase.outputs.connectionString
output keyVaultUri string = keyVault.outputs.uri
```

## Módulos

### Container App Environment

```bicep
// modules/container-app-env.bicep
@description('Environment name')
param name string

@description('Location')
param location string

@description('Tags')
param tags object = {}

@description('Log Analytics Workspace ID')
param logAnalyticsWorkspaceId string

resource containerAppEnv 'Microsoft.App/managedEnvironments@2023-05-01' = {
  name: name
  location: location
  tags: tags
  properties: {
    appLogsConfiguration: {
      destination: 'log-analytics'
      logAnalyticsConfiguration: {
        customerId: reference(logAnalyticsWorkspaceId, '2022-10-01').customerId
        sharedKey: listKeys(logAnalyticsWorkspaceId, '2022-10-01').primarySharedKey
      }
    }
  }
}

output id string = containerAppEnv.id
output name string = containerAppEnv.name
```

### Container App

```bicep
// modules/container-app.bicep
@description('App name')
param name string

@description('Location')
param location string

@description('Tags')
param tags object = {}

@description('Container App Environment ID')
param environmentId string

@description('Container image')
param containerImage string

@description('App Insights connection string')
param appInsightsConnectionString string = ''

@description('CPU cores')
param cpu string = '0.25'

@description('Memory')
param memory string = '0.5Gi'

@description('Min replicas')
param minReplicas int = 0

@description('Max replicas')
param maxReplicas int = 3

resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
  name: name
  location: location
  tags: tags
  properties: {
    managedEnvironmentId: environmentId
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
        transport: 'http'
        allowInsecure: false
      }
      secrets: appInsightsConnectionString != '' ? [
        {
          name: 'appinsights-connection-string'
          value: appInsightsConnectionString
        }
      ] : []
    }
    template: {
      containers: [
        {
          name: name
          image: containerImage
          resources: {
            cpu: json(cpu)
            memory: memory
          }
          env: appInsightsConnectionString != '' ? [
            {
              name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
              secretRef: 'appinsights-connection-string'
            }
          ] : []
        }
      ]
      scale: {
        minReplicas: minReplicas
        maxReplicas: maxReplicas
        rules: [
          {
            name: 'http-scale'
            http: {
              metadata: {
                concurrentRequests: '100'
              }
            }
          }
        ]
      }
    }
  }
}

output id string = containerApp.id
output name string = containerApp.name
output url string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
```

### SQL Database (Free Tier)

```bicep
// modules/sql-database.bicep
@description('SQL Server name')
param serverName string

@description('Database name')
param databaseName string

@description('Location')
param location string

@description('Tags')
param tags object = {}

@description('Admin username')
param adminUsername string = 'sqladmin'

@description('Admin password')
@secure()
param adminPassword string

@description('Use free tier')
param useFree bool = true

resource sqlServer 'Microsoft.Sql/servers@2023-05-01-preview' = {
  name: serverName
  location: location
  tags: tags
  properties: {
    administratorLogin: adminUsername
    administratorLoginPassword: adminPassword
    version: '12.0'
    minimalTlsVersion: '1.2'
    publicNetworkAccess: 'Enabled'
  }
}

resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = {
  parent: sqlServer
  name: databaseName
  location: location
  tags: tags
  sku: useFree ? {
    name: 'Free'
    tier: 'Free'
  } : {
    name: 'Basic'
    tier: 'Basic'
  }
  properties: {
    collation: 'SQL_Latin1_General_CP1_CI_AS'
    maxSizeBytes: useFree ? 32212254720 : 2147483648  // 32GB free, 2GB basic
  }
}

// Allow Azure services
resource firewallRule 'Microsoft.Sql/servers/firewallRules@2023-05-01-preview' = {
  parent: sqlServer
  name: 'AllowAllAzureIps'
  properties: {
    startIpAddress: '0.0.0.0'
    endIpAddress: '0.0.0.0'
  }
}

output connectionString string = 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Database=${databaseName};User ID=${adminUsername};Password=${adminPassword};Encrypt=true;Connection Timeout=30;'
output serverFqdn string = sqlServer.properties.fullyQualifiedDomainName
```

## Commands

```bash
# Validar Bicep
az bicep build --file infra/main.bicep

# What-if (preview de mudanças)
az deployment group what-if \
  --resource-group rg-myapp-dev \
  --template-file infra/main.bicep \
  --parameters @infra/parameters.dev.json

# Deploy
az deployment group create \
  --resource-group rg-myapp-dev \
  --template-file infra/main.bicep \
  --parameters @infra/parameters.dev.json

# Criar resource group primeiro
az group create --name rg-myapp-dev --location brazilsouth

# Deletar deployment
az group delete --name rg-myapp-dev --yes --no-wait
```

## Parameters File

```json
// parameters.dev.json
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "environment": {
      "value": "dev"
    },
    "appName": {
      "value": "myapp"
    },
    "sqlAdminPassword": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{kv-name}"
        },
        "secretName": "sql-admin-password"
      }
    }
  }
}
```

## Documentação de Referência

- [Azure Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/)
- [Bicep Reference](https://learn.microsoft.com/en-us/azure/templates/)
- [Bicep Modules](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/modules)
- [Best Practices](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/best-practices)

## Checklist de IaC

- [ ] Bicep válido (`az bicep build`)
- [ ] Modules para recursos reutilizáveis
- [ ] Parâmetros para dev e prod
- [ ] Secrets referenciados do Key Vault
- [ ] Tags em todos os recursos
- [ ] What-if executado antes de deploy
- [ ] Outputs para valores importantes
- [ ] Documentação dos parâmetros

---

*MORPH-SPEC by Polymorphism Tech*
