diff --git a/5_analytics-bigdata/README.md b/5_analytics-bigdata/README.md
index bf7179a..e9f6942 100644
--- a/5_analytics-bigdata/README.md
+++ b/5_analytics-bigdata/README.md
@@ -5,7 +5,7 @@ Costa Rica
[](https://github.com/)
[brown9804](https://github.com/brown9804)
-Last updated: 2026-02-12
+Last updated: 2026-02-16
------------------------------------------
@@ -16,6 +16,8 @@ Last updated: 2026-02-12
- [Azure Data Factory](./data-factory)
- [Azure Databricks (Workspace)](./databricks)
+- [Azure Event Hubs](./event-hub)
+- [Microsoft Fabric (Capacity)](./fabric)
- [Azure Synapse Analytics (Workspace)](./synapse-analytics)
diff --git a/5_analytics-bigdata/fabric/README.md b/5_analytics-bigdata/fabric/README.md
new file mode 100644
index 0000000..6d3c624
--- /dev/null
+++ b/5_analytics-bigdata/fabric/README.md
@@ -0,0 +1,85 @@
+# Terraform Template - Microsoft Fabric (Capacity)
+
+Costa Rica
+
+[](https://github.com/)
+[brown9804](https://github.com/brown9804)
+
+Last updated: 2026-02-16
+
+------------------------------------------
+
+> This template contains Terraform configurations to create a Microsoft Fabric capacity in Azure.
+
+> [!IMPORTANT]
+> Fabric capacity creation requires at least one admin member.
+>
+> - Option A (recommended): set `use_current_user_as_admin = true` and let Terraform resolve the current user UPN.
+> - Option B: set `admin_members` explicitly to one or more UPNs like `user@domain.com`.
+> To avoid committing identities, prefer environment variables:
+> - PowerShell: `$env:TF_VAR_admin_members='["user@domain.com"]'`
+> - PowerShell (auto): keep `use_current_user_as_admin = true` and omit `admin_members`.
+
+> [!NOTE]
+>
+> - The Fabric capacity resource is created via the AzAPI provider using the ARM resource type `Microsoft.Fabric/capacities@2023-11-01`.
+> - The Resource Group is created via AzAPI (idempotent ARM PUT) to align with other templates in this repository.
+
+
+
+
+
+
+
+## File Descriptions
+
+- **main.tf**: Creates the Resource Group and the Fabric capacity (AzAPI).
+- **variables.tf**: Defines the input variables used in the Terraform configuration.
+- **provider.tf**: Configures the AzureRM + AzAPI providers.
+- **terraform.tfvars**: Example values for the variables defined in `variables.tf`.
+- **output.tf**: Defines outputs such as Fabric capacity resource ID.
+
+## Variables
+
+| Variable Name | Description | Type | Example Value |
+| --- | --- | --- | --- |
+| `resource_group_name` | Resource Group name to create/deploy into. | string | `"rg-analytics-dev-fabric"` |
+| `location` | Azure region for the deployment. | string | `"eastus"` |
+| `capacity_name` | Base capacity name. If suffix enabled, final is `-`. | string | `"fabric-capacity-dev"` |
+| `use_current_user_as_admin` | Auto-resolve current user as admin when `admin_members` is empty. | bool | `true` |
+| `admin_members` | Optional explicit Fabric capacity admins (UPNs). Overrides auto mode. | list(string) | `[]` |
+| `sku_name` | Capacity SKU (for example `F2`, `F4`, `F8`, ...). | string | `"F2"` |
+| `sku_tier` | Capacity SKU tier. | string | `"Fabric"` |
+| `append_random_suffix` | Append a random suffix to avoid collisions. | bool | `true` |
+| `random_suffix_length` | Length of the random suffix when enabled. | number | `6` |
+| `tags` | Tags applied to resources. | map(string) | `{ "env": "dev" }` |
+
+## Usage
+
+1. Authenticate:
+
+ ```sh
+ az login
+ az account show
+ # If needed:
+ az account set --subscription ""
+ ```
+
+2. Initialize:
+
+ ```sh
+ terraform init -upgrade
+ ```
+
+3. Validate and plan:
+
+ ```sh
+ terraform validate
+ terraform plan
+ ```
+
+4. Apply:
+
+ ```sh
+ terraform apply -auto-approve
+ ```
diff --git a/5_analytics-bigdata/fabric/main.tf b/5_analytics-bigdata/fabric/main.tf
new file mode 100644
index 0000000..7478bfa
--- /dev/null
+++ b/5_analytics-bigdata/fabric/main.tf
@@ -0,0 +1,96 @@
+data "azurerm_client_config" "current" {}
+
+data "azuread_client_config" "current" {}
+
+data "azuread_user" "current" {
+ object_id = data.azuread_client_config.current.object_id
+}
+
+# Resource group creation is idempotent in ARM (PUT). This will create the RG if it doesn't exist,
+# or update tags if it already exists.
+resource "azapi_resource" "resource_group" {
+ type = "Microsoft.Resources/resourceGroups@2022-09-01"
+ name = var.resource_group_name
+ location = var.location
+ parent_id = "/subscriptions/${data.azurerm_client_config.current.subscription_id}"
+
+ body = jsonencode({
+ tags = var.tags
+ })
+
+ response_export_values = [
+ "id",
+ "name"
+ ]
+}
+
+resource "random_string" "suffix" {
+ length = var.random_suffix_length
+ upper = false
+ special = false
+ numeric = true
+
+ keepers = {
+ resource_group_name = var.resource_group_name
+ location = var.location
+ capacity_base = var.capacity_name
+ sku_name = var.sku_name
+ sku_tier = var.sku_tier
+ }
+}
+
+locals {
+ rg_id = azapi_resource.resource_group.id
+ suffix = var.append_random_suffix ? random_string.suffix.result : ""
+ capacity_name = var.append_random_suffix ? "${var.capacity_name}-${local.suffix}" : var.capacity_name
+
+ # AzAPI schema validation for Microsoft.Fabric/capacities currently enforces a strict name pattern:
+ # ^[a-z][a-z0-9]*$
+ # To keep tfvars friendly (allowing '-' etc.), we sanitize the requested name for the ARM resource name.
+ capacity_name_sanitized_raw = join("", regexall("[a-z0-9]", lower(local.capacity_name)))
+ capacity_name_sanitized = can(regex("^[a-z]", local.capacity_name_sanitized_raw)) ? local.capacity_name_sanitized_raw : "fc${local.capacity_name_sanitized_raw}"
+
+ admin_members_effective = (
+ length(var.admin_members) > 0
+ ? var.admin_members
+ : (var.use_current_user_as_admin ? [data.azuread_user.current.user_principal_name] : [])
+ )
+}
+
+# Microsoft Fabric capacity (ARM resource provider: Microsoft.Fabric)
+# API version reference: https://learn.microsoft.com/azure/templates/Microsoft.Fabric/2023-11-01/capacities
+resource "azapi_resource" "fabric_capacity" {
+ type = "Microsoft.Fabric/capacities@2023-11-01"
+ name = local.capacity_name_sanitized
+ location = var.location
+ parent_id = local.rg_id
+
+ lifecycle {
+ precondition {
+ condition = length(local.admin_members_effective) > 0
+ error_message = "No Fabric admins configured. Set admin_members (list of UPNs) or enable use_current_user_as_admin to auto-resolve the current user."
+ }
+ }
+
+ body = jsonencode({
+ sku = {
+ name = var.sku_name
+ tier = var.sku_tier
+ }
+ properties = {
+ administration = {
+ members = local.admin_members_effective
+ }
+ }
+ tags = var.tags
+ })
+
+ response_export_values = [
+ "id",
+ "name"
+ ]
+
+ depends_on = [
+ azapi_resource.resource_group
+ ]
+}
diff --git a/5_analytics-bigdata/fabric/output.tf b/5_analytics-bigdata/fabric/output.tf
new file mode 100644
index 0000000..ccd8ef4
--- /dev/null
+++ b/5_analytics-bigdata/fabric/output.tf
@@ -0,0 +1,24 @@
+output "resource_group_id" {
+ description = "The resource ID of the Resource Group."
+ value = azapi_resource.resource_group.id
+}
+
+output "fabric_capacity_id" {
+ description = "The resource ID of the Fabric capacity."
+ value = azapi_resource.fabric_capacity.id
+}
+
+output "fabric_capacity_name" {
+ description = "The name of the Fabric capacity (sanitized ARM resource name)."
+ value = azapi_resource.fabric_capacity.name
+}
+
+output "fabric_capacity_name_requested" {
+ description = "The requested capacity_name value after suffixing (before sanitization)."
+ value = local.capacity_name
+}
+
+output "fabric_capacity_location" {
+ description = "The Azure region the Fabric capacity is deployed into."
+ value = var.location
+}
diff --git a/5_analytics-bigdata/fabric/provider.tf b/5_analytics-bigdata/fabric/provider.tf
new file mode 100644
index 0000000..78dd546
--- /dev/null
+++ b/5_analytics-bigdata/fabric/provider.tf
@@ -0,0 +1,48 @@
+# provider.tf
+# This file configures the Azure provider to interact with Azure resources.
+# It specifies the required provider and its version, along with provider-specific configurations.
+
+terraform {
+ required_version = ">= 1.8, < 2.0"
+
+ required_providers {
+ azurerm = {
+ source = "hashicorp/azurerm"
+ version = "~> 3.116"
+ }
+
+ azapi = {
+ source = "Azure/azapi"
+ version = "~> 1.13"
+ }
+
+ random = {
+ source = "hashicorp/random"
+ version = "~> 3.6"
+ }
+
+ azuread = {
+ source = "hashicorp/azuread"
+ version = "~> 3.0"
+ }
+ }
+}
+
+provider "azurerm" {
+ features {
+ resource_group {
+ prevent_deletion_if_contains_resources = false
+ }
+ }
+
+ # Uses the current Azure CLI context (az login + az account set)
+ skip_provider_registration = false
+}
+
+provider "azapi" {
+ # Uses the current Azure CLI context (az login + az account set)
+}
+
+provider "azuread" {
+ # Uses the current Azure CLI context (az login + az account set)
+}
diff --git a/5_analytics-bigdata/fabric/terraform.tfvars b/5_analytics-bigdata/fabric/terraform.tfvars
new file mode 100644
index 0000000..085ed29
--- /dev/null
+++ b/5_analytics-bigdata/fabric/terraform.tfvars
@@ -0,0 +1,23 @@
+resource_group_name = "rg-analytics-dev-fabric"
+location = "eastus"
+
+append_random_suffix = true
+random_suffix_length = 6
+
+capacity_name = "fabric-capacity-dev"
+
+use_current_user_as_admin = true
+
+# Optional override (UPNs):
+# admin_members = [
+# "user@domain.com"
+# ]
+
+sku_name = "F2"
+sku_tier = "Fabric"
+
+tags = {
+ env = "dev"
+ area = "analytics-bigdata"
+ iac = "terraform"
+}
diff --git a/5_analytics-bigdata/fabric/variables.tf b/5_analytics-bigdata/fabric/variables.tf
new file mode 100644
index 0000000..7b0a30f
--- /dev/null
+++ b/5_analytics-bigdata/fabric/variables.tf
@@ -0,0 +1,80 @@
+variable "resource_group_name" {
+ description = "The name of the Azure Resource Group to deploy into. This template will create the RG if it does not exist (idempotent ARM PUT)."
+ type = string
+
+ validation {
+ condition = length(trimspace(var.resource_group_name)) > 0
+ error_message = "resource_group_name must not be empty."
+ }
+}
+
+variable "location" {
+ description = "The Azure region where the Resource Group and Fabric capacity will be created."
+ type = string
+
+ validation {
+ condition = length(trimspace(var.location)) > 0
+ error_message = "location must not be empty."
+ }
+}
+
+variable "append_random_suffix" {
+ description = "Whether to append a random suffix to the capacity name to avoid collisions."
+ type = bool
+ default = true
+}
+
+variable "random_suffix_length" {
+ description = "Length of the random suffix appended when append_random_suffix is true."
+ type = number
+ default = 6
+
+ validation {
+ condition = var.random_suffix_length >= 4 && var.random_suffix_length <= 16
+ error_message = "random_suffix_length must be between 4 and 16."
+ }
+}
+
+variable "capacity_name" {
+ description = "Base name of the Fabric capacity. If append_random_suffix is true, the final name will be '-'."
+ type = string
+
+ validation {
+ condition = (
+ length(trimspace(var.capacity_name)) > 0
+ && length(var.capacity_name) <= (var.append_random_suffix ? (63 - 1 - var.random_suffix_length) : 63)
+ && length(join("", regexall("[a-z0-9]", lower(var.capacity_name)))) > 0
+ )
+ error_message = "capacity_name must be 1-63 chars and must contain at least one letter or digit (Terraform will sanitize the name to meet Azure resource naming constraints)."
+ }
+}
+
+variable "admin_members" {
+ description = "Optional list of Fabric capacity admin members (UPNs). If empty and use_current_user_as_admin is true, Terraform will resolve the current user and use that UPN."
+ type = list(string)
+ default = []
+}
+
+variable "use_current_user_as_admin" {
+ description = "When true and admin_members is empty, resolve the currently authenticated Entra ID user and set them as the Fabric capacity admin. Requires AzureAD (Microsoft Graph) read permissions to resolve the UPN."
+ type = bool
+ default = true
+}
+
+variable "sku_name" {
+ description = "SKU name for the Fabric capacity (for example: F2, F4, F8, F16, F32, F64, F128, F256, F512, F1024, F2048)."
+ type = string
+ default = "F2"
+}
+
+variable "sku_tier" {
+ description = "SKU tier for the Fabric capacity."
+ type = string
+ default = "Fabric"
+}
+
+variable "tags" {
+ description = "A map of tags to assign to the resources."
+ type = map(string)
+ default = {}
+}
diff --git a/README.md b/README.md
index 2f852e9..0919611 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Costa Rica
[](https://github.com/)
[brown9804](https://github.com/brown9804)
-Last updated: 2026-02-12
+Last updated: 2026-02-16
----------
@@ -107,6 +107,8 @@ Last updated: 2026-02-12
- [Analytics and Big Data](./5_analytics-bigdata)
- [Azure Data Factory](./5_analytics-bigdata/data-factory)
- [Azure Databricks (Workspace)](./5_analytics-bigdata/databricks)
+ - [Azure Event Hubs](./5_analytics-bigdata/event-hub)
+ - [Microsoft Fabric (Capacity)](./5_analytics-bigdata/fabric)
- [Azure Synapse Analytics (Workspace)](./5_analytics-bigdata/synapse-analytics)