# Function Template Recipes

Composable IaC + source code modules that extend the HTTP base template
to support specific Azure service integrations.

## Architecture

```
HTTP Base Template (per language, from AZD gallery)
       │
       ├── Source code (HTTP GET/POST)
       ├── IaC (Storage, App Insights, Flex Plan, UAMI, RBAC, VNet)
       └── AZD config (azure.yaml, parameters)

       + Recipe (per integration)
       │
       ├── Source code delta (trigger/binding snippet)
       ├── IaC delta (new resource + RBAC + networking modules)
       └── App settings delta
       │
       = Complete deployable project → `azd up`
```

## Common Patterns

All recipes should use these shared patterns:

| Pattern | File | Description |
|---------|------|-------------|
| [UAMI Bindings](common/uami-bindings.md) | `common/uami-bindings.md` | **MANDATORY** — App settings for managed identity connections |
| [Error Handling](common/error-handling.md) | `common/error-handling.md` | Try/catch + logging patterns per language |
| [Health Check](common/health-check.md) | `common/health-check.md` | Health endpoint for monitoring/load balancers |

## Available Recipes

| Recipe | IaC Delta? | Source Delta? | Status |
|--------|-----------|--------------|--------|
| [cosmosdb](cosmosdb/README.md) | ✅ Cosmos account + DB + containers + RBAC + PE | ✅ CosmosDBTrigger | ✅ Available |
| [eventhubs](eventhubs/README.md) | ✅ EH namespace + hub + consumer group + RBAC + PE | ✅ EventHubTrigger | ✅ Available |
| [servicebus](servicebus/README.md) | ✅ SB namespace + queue + RBAC + PE | ✅ ServiceBusTrigger | ✅ Available |
| [timer](timer/README.md) | ❌ None | ✅ TimerTrigger + cron | ✅ Available |
| [durable](durable/README.md) | ⚠️ Storage flags (enableQueue/Table) | ✅ Orchestrator + Activity + Client | ✅ Available |
| [mcp](mcp/README.md) | ⚠️ Storage flag (enableQueue) | ✅ MCP JSON-RPC tools | ✅ Available |
| [sql](sql/README.md) | ✅ SQL server + DB + firewall + identity | ✅ SqlTrigger | ✅ Available |
| [blob-eventgrid](blob-eventgrid/README.md) | ✅ EventGrid subscription + system topic | ✅ BlobTrigger (EG) | ✅ Available |

## How It Works

### Step 1: Fetch HTTP Base

```bash
# Bicep base (default) - template name varies by language
# C#:         azd init -t functions-quickstart-dotnet-azd
# TypeScript: azd init -t functions-quickstart-typescript-azd  
# JavaScript: azd init -t functions-quickstart-javascript-azd
# Python:     azd init -t functions-quickstart-python-http-azd  ← Note: "python-http"
# Java:       azd init -t azure-functions-java-flex-consumption-azd
# PowerShell: azd init -t functions-quickstart-powershell-azd

# Terraform base (append -tf)
# Same names as above with -tf suffix
```

### Step 2: Apply Recipe

The skill reads the recipe's README.md for:
- **IaC module files** to copy into `infra/`
- **App settings** to add to function app config
- **RBAC roles** with exact GUIDs (never generated by LLM)
- **Source code** to replace HTTP trigger with integration trigger
- **Networking** to add private endpoints (conditional on VNET_ENABLED)

### Step 3: Wire Into Base

**Bicep:** Add `module` reference in `main.bicep`, pass `functionAppPrincipalId`
**Terraform:** Copy `.tf` file into `infra/`, merge `locals.cosmos_app_settings` into function app

### Step 4: Deploy

**Set required environment variables:**
```bash
azd env set AZURE_LOCATION eastus2
azd env set VNET_ENABLED false
```

**Deploy (two-phase recommended for reliability):**
```bash
azd provision --no-prompt     # Create resources + RBAC
sleep 60                       # Wait for RBAC propagation
azd deploy --no-prompt        # Deploy code
```

> **Note:** If `azd up` fails with 403 storage errors, RBAC hasn't propagated yet.
> Never enable `allowSharedKeyAccess` — just wait and retry.

## Design Principles

| Principle | Why |
|-----------|-----|
| **Never synthesize base IaC** | Always use proven AZD template repos |
| **Never modify base; only extend** | Recipes are additive modules — no risk of breaking core |
| **Recipes own their RBAC** | Exact role GUIDs, no LLM guessing |
| **Recipes own their networking** | Private endpoints per service, fully tested |
| **Same algorithm for Bicep & Terraform** | Only IaC files differ, not composition logic |
| **Source snippets per language** | Small, deterministic, tested code blocks |

## Base Templates

| Language | Bicep Template | Terraform Template |
|----------|---------------|-------------------|
| C# (.NET) | `functions-quickstart-dotnet-azd` | `functions-quickstart-dotnet-azd-tf` |
| TypeScript | `functions-quickstart-typescript-azd` | `functions-quickstart-dotnet-azd-tf` * |
| JavaScript | `functions-quickstart-javascript-azd` | `functions-quickstart-dotnet-azd-tf` * |
| Python | `functions-quickstart-python-http-azd` | `functions-quickstart-dotnet-azd-tf` * |
| Java | `azure-functions-java-flex-consumption-azd` | `functions-quickstart-dotnet-azd-tf` * |
| PowerShell | `functions-quickstart-powershell-azd` | `functions-quickstart-dotnet-azd-tf` * |

> \* **Terraform Note**: Only `functions-quickstart-dotnet-azd-tf` exists. For other languages:
> 1. Initialize with `azd init -t functions-quickstart-dotnet-azd-tf`
> 2. Change runtime settings in `main.tf`: `runtime = { name = "node", version = "22" }`
> 3. Replace source code with your language's files
>
> See [composition.md](composition.md) for the full algorithm.
