# PLAT-11: live WO tables are kebab-case (PascalCase destroyed). resource "aws_dynamodb_table" "work_orders_kebab" { name = "work-orders" billing_mode = "PAY_PER_REQUEST" hash_key = "work_order_id" deletion_protection_enabled = true attribute { name = "work_order_id" type = "S" } stream_enabled = true stream_view_type = "NEW_AND_OLD_IMAGES" point_in_time_recovery { enabled = true } lifecycle { prevent_destroy = true } } resource "aws_dynamodb_table" "work_order_comments_kebab" { name = "work-order-comments" billing_mode = "PAY_PER_REQUEST" hash_key = "work_order_id" range_key = "comment_id" deletion_protection_enabled = true attribute { name = "work_order_id" type = "S" } attribute { name = "comment_id" type = "S" } stream_enabled = true stream_view_type = "NEW_AND_OLD_IMAGES" point_in_time_recovery { enabled = true } lifecycle { prevent_destroy = true } } locals { # Alarms follow live writer tables after PLAT-11 cutover. wo_ddb_alarm_tables = { "work-orders" = aws_dynamodb_table.work_orders_kebab.name "work-order-comments" = aws_dynamodb_table.work_order_comments_kebab.name } } resource "aws_cloudwatch_metric_alarm" "wo_ddb_throttles" { for_each = local.wo_ddb_alarm_tables alarm_name = "${each.key}-throttles" alarm_description = "${each.key} DynamoDB throttled requests" comparison_operator = "GreaterThanThreshold" evaluation_periods = 1 threshold = 0 treat_missing_data = "notBreaching" alarm_actions = [data.aws_sns_topic.site_alerts.arn] metric_query { id = "expr_1" expression = local.ddb_throttle_expr label = "Sum of throttled requests across all operations" return_data = true } dynamic "metric_query" { for_each = local.ddb_alarm_operations content { id = lower(metric_query.value) metric { metric_name = "ThrottledRequests" namespace = "AWS/DynamoDB" period = 300 stat = "Sum" dimensions = { TableName = each.value Operation = metric_query.value } } return_data = false } } } resource "aws_cloudwatch_metric_alarm" "wo_ddb_system_errors" { for_each = local.wo_ddb_alarm_tables alarm_name = "${each.key}-system-errors" alarm_description = "${each.key} DynamoDB server-side (5xx) errors" comparison_operator = "GreaterThanThreshold" evaluation_periods = 1 threshold = 0 treat_missing_data = "notBreaching" alarm_actions = [data.aws_sns_topic.site_alerts.arn] metric_query { id = "expr_1" expression = local.ddb_throttle_expr label = "Sum of system errors across all operations" return_data = true } dynamic "metric_query" { for_each = local.ddb_alarm_operations content { id = lower(metric_query.value) metric { metric_name = "SystemErrors" namespace = "AWS/DynamoDB" period = 300 stat = "Sum" dimensions = { TableName = each.value Operation = metric_query.value } } return_data = false } } }