mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 10:24:02 +00:00
feat(WHE-28): add terraform baseline for cloud run and scheduler
This commit is contained in:
4
infra/terraform/.gitignore
vendored
Normal file
4
infra/terraform/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.terraform
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
terraform.tfvars
|
||||
22
infra/terraform/.terraform.lock.hcl
generated
Normal file
22
infra/terraform/.terraform.lock.hcl
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/google" {
|
||||
version = "6.50.0"
|
||||
constraints = "~> 6.0"
|
||||
hashes = [
|
||||
"h1:79CwMTsp3Ud1nOl5hFS5mxQHyT0fGVye7pqpU0PPlHI=",
|
||||
"zh:1f3513fcfcbf7ca53d667a168c5067a4dd91a4d4cccd19743e248ff31065503c",
|
||||
"zh:3da7db8fc2c51a77dd958ea8baaa05c29cd7f829bd8941c26e2ea9cb3aadc1e5",
|
||||
"zh:3e09ac3f6ca8111cbb659d38c251771829f4347ab159a12db195e211c76068bb",
|
||||
"zh:7bb9e41c568df15ccf1a8946037355eefb4dfb4e35e3b190808bb7c4abae547d",
|
||||
"zh:81e5d78bdec7778e6d67b5c3544777505db40a826b6eb5abe9b86d4ba396866b",
|
||||
"zh:8d309d020fb321525883f5c4ea864df3d5942b6087f6656d6d8b3a1377f340fc",
|
||||
"zh:93e112559655ab95a523193158f4a4ac0f2bfed7eeaa712010b85ebb551d5071",
|
||||
"zh:d3efe589ffd625b300cef5917c4629513f77e3a7b111c9df65075f76a46a63c7",
|
||||
"zh:d4a4d672bbef756a870d8f32b35925f8ce2ef4f6bbd5b71a3cb764f1b6c85421",
|
||||
"zh:e13a86bca299ba8a118e80d5f84fbdd708fe600ecdceea1a13d4919c068379fe",
|
||||
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
|
||||
"zh:fec30c095647b583a246c39d557704947195a1b7d41f81e369ba377d997faef6",
|
||||
]
|
||||
}
|
||||
79
infra/terraform/README.md
Normal file
79
infra/terraform/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Terraform Infrastructure (WHE-28)
|
||||
|
||||
This directory contains baseline IaC for deploying the household bot platform on GCP.
|
||||
|
||||
## Provisioned resources
|
||||
|
||||
- Artifact Registry Docker repository
|
||||
- Cloud Run service: bot API (public webhook endpoint)
|
||||
- Cloud Run service: mini app (public web UI)
|
||||
- Cloud Scheduler job for reminder triggers
|
||||
- Runtime and scheduler service accounts with least-privilege bindings
|
||||
- Secret Manager secrets (IDs only, secret values are added separately)
|
||||
- Optional GitHub OIDC Workload Identity setup for deploy automation
|
||||
|
||||
## Architecture (v1)
|
||||
|
||||
- `bot-api`: Telegram webhook + app API endpoints
|
||||
- `mini-app`: front-end delivery
|
||||
- `scheduler`: triggers `bot-api` internal reminder endpoint using OIDC token
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Terraform `>= 1.8`
|
||||
- Authenticated GCP CLI context (`gcloud auth application-default login` for local)
|
||||
- Enabled billing on the target GCP project
|
||||
|
||||
## Usage
|
||||
|
||||
1. Initialize:
|
||||
|
||||
```bash
|
||||
terraform -chdir=infra/terraform init
|
||||
```
|
||||
|
||||
2. Prepare variables:
|
||||
|
||||
```bash
|
||||
cp infra/terraform/terraform.tfvars.example infra/terraform/terraform.tfvars
|
||||
```
|
||||
|
||||
3. Plan:
|
||||
|
||||
```bash
|
||||
terraform -chdir=infra/terraform plan
|
||||
```
|
||||
|
||||
4. Apply:
|
||||
|
||||
```bash
|
||||
terraform -chdir=infra/terraform apply
|
||||
```
|
||||
|
||||
5. Add secret values (after apply):
|
||||
|
||||
```bash
|
||||
echo -n "<value>" | gcloud secrets versions add telegram-webhook-secret --data-file=- --project <project_id>
|
||||
echo -n "<value>" | gcloud secrets versions add scheduler-shared-secret --data-file=- --project <project_id>
|
||||
```
|
||||
|
||||
## Environments
|
||||
|
||||
Recommended approach:
|
||||
|
||||
- Keep one state per environment (dev/prod) using separate backend configs or workspaces
|
||||
- Use `terraform.tfvars` per environment (`dev.tfvars`, `prod.tfvars`)
|
||||
- Keep `project_id` separate for dev/prod when possible
|
||||
|
||||
## CI validation
|
||||
|
||||
CI runs:
|
||||
|
||||
- `terraform -chdir=infra/terraform fmt -check -recursive`
|
||||
- `terraform -chdir=infra/terraform init -backend=false`
|
||||
- `terraform -chdir=infra/terraform validate`
|
||||
|
||||
## Notes
|
||||
|
||||
- Scheduler job defaults to `paused = true` to prevent accidental sends before app logic is ready.
|
||||
- Bot API is public to accept Telegram webhooks; scheduler endpoint should still verify app-level auth.
|
||||
37
infra/terraform/locals.tf
Normal file
37
infra/terraform/locals.tf
Normal file
@@ -0,0 +1,37 @@
|
||||
locals {
|
||||
name_prefix = "${var.service_prefix}-${var.environment}"
|
||||
|
||||
common_labels = merge(
|
||||
{
|
||||
environment = var.environment
|
||||
managed_by = "terraform"
|
||||
project = "household-bot"
|
||||
},
|
||||
var.labels
|
||||
)
|
||||
|
||||
artifact_location = coalesce(var.artifact_repository_location, var.region)
|
||||
|
||||
runtime_secret_ids = toset(compact([
|
||||
var.telegram_webhook_secret_id,
|
||||
var.scheduler_shared_secret_id,
|
||||
var.supabase_url_secret_id,
|
||||
var.supabase_publishable_key_secret_id
|
||||
]))
|
||||
|
||||
api_services = toset([
|
||||
"artifactregistry.googleapis.com",
|
||||
"cloudscheduler.googleapis.com",
|
||||
"iam.googleapis.com",
|
||||
"iamcredentials.googleapis.com",
|
||||
"run.googleapis.com",
|
||||
"secretmanager.googleapis.com",
|
||||
"sts.googleapis.com"
|
||||
])
|
||||
|
||||
github_deploy_roles = toset([
|
||||
"roles/artifactregistry.writer",
|
||||
"roles/iam.serviceAccountUser",
|
||||
"roles/run.admin"
|
||||
])
|
||||
}
|
||||
218
infra/terraform/main.tf
Normal file
218
infra/terraform/main.tf
Normal file
@@ -0,0 +1,218 @@
|
||||
data "google_project" "current" {
|
||||
project_id = var.project_id
|
||||
}
|
||||
|
||||
resource "google_project_service" "enabled" {
|
||||
for_each = local.api_services
|
||||
project = var.project_id
|
||||
service = each.value
|
||||
disable_on_destroy = false
|
||||
disable_dependent_services = false
|
||||
}
|
||||
|
||||
resource "google_artifact_registry_repository" "containers" {
|
||||
location = local.artifact_location
|
||||
project = var.project_id
|
||||
repository_id = var.artifact_repository_id
|
||||
description = "Container images for household bot"
|
||||
format = "DOCKER"
|
||||
|
||||
labels = local.common_labels
|
||||
|
||||
depends_on = [google_project_service.enabled]
|
||||
}
|
||||
|
||||
resource "google_service_account" "bot_runtime" {
|
||||
project = var.project_id
|
||||
account_id = "${var.environment}-bot-runtime"
|
||||
display_name = "${local.name_prefix} bot runtime"
|
||||
}
|
||||
|
||||
resource "google_service_account" "mini_runtime" {
|
||||
project = var.project_id
|
||||
account_id = "${var.environment}-mini-runtime"
|
||||
display_name = "${local.name_prefix} mini runtime"
|
||||
}
|
||||
|
||||
resource "google_service_account" "scheduler_invoker" {
|
||||
project = var.project_id
|
||||
account_id = "${var.environment}-scheduler"
|
||||
display_name = "${local.name_prefix} scheduler invoker"
|
||||
}
|
||||
|
||||
resource "google_secret_manager_secret" "runtime" {
|
||||
for_each = local.runtime_secret_ids
|
||||
|
||||
project = var.project_id
|
||||
secret_id = each.value
|
||||
|
||||
replication {
|
||||
auto {}
|
||||
}
|
||||
|
||||
labels = local.common_labels
|
||||
|
||||
depends_on = [google_project_service.enabled]
|
||||
}
|
||||
|
||||
resource "google_secret_manager_secret_iam_member" "bot_runtime_access" {
|
||||
for_each = google_secret_manager_secret.runtime
|
||||
|
||||
project = var.project_id
|
||||
secret_id = each.value.secret_id
|
||||
role = "roles/secretmanager.secretAccessor"
|
||||
member = "serviceAccount:${google_service_account.bot_runtime.email}"
|
||||
}
|
||||
|
||||
module "bot_api_service" {
|
||||
source = "./modules/cloud_run_service"
|
||||
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
name = "${local.name_prefix}-bot-api"
|
||||
service_account_email = google_service_account.bot_runtime.email
|
||||
image = var.bot_api_image
|
||||
allow_unauthenticated = true
|
||||
min_instance_count = var.bot_min_instances
|
||||
max_instance_count = var.bot_max_instances
|
||||
labels = local.common_labels
|
||||
|
||||
env = {
|
||||
NODE_ENV = var.environment
|
||||
}
|
||||
|
||||
secret_env = merge(
|
||||
{
|
||||
TELEGRAM_WEBHOOK_SECRET = var.telegram_webhook_secret_id
|
||||
SCHEDULER_SHARED_SECRET = var.scheduler_shared_secret_id
|
||||
},
|
||||
var.supabase_url_secret_id == null ? {} : {
|
||||
SUPABASE_URL = var.supabase_url_secret_id
|
||||
},
|
||||
var.supabase_publishable_key_secret_id == null ? {} : {
|
||||
SUPABASE_PUBLISHABLE_KEY = var.supabase_publishable_key_secret_id
|
||||
}
|
||||
)
|
||||
|
||||
depends_on = [
|
||||
google_project_service.enabled,
|
||||
google_secret_manager_secret.runtime
|
||||
]
|
||||
}
|
||||
|
||||
module "mini_app_service" {
|
||||
source = "./modules/cloud_run_service"
|
||||
|
||||
project_id = var.project_id
|
||||
region = var.region
|
||||
name = "${local.name_prefix}-mini-app"
|
||||
service_account_email = google_service_account.mini_runtime.email
|
||||
image = var.mini_app_image
|
||||
allow_unauthenticated = true
|
||||
min_instance_count = var.mini_min_instances
|
||||
max_instance_count = var.mini_max_instances
|
||||
labels = local.common_labels
|
||||
|
||||
env = {
|
||||
NODE_ENV = var.environment
|
||||
}
|
||||
|
||||
depends_on = [google_project_service.enabled]
|
||||
}
|
||||
|
||||
resource "google_cloud_run_v2_service_iam_member" "scheduler_invoker" {
|
||||
project = var.project_id
|
||||
location = var.region
|
||||
name = module.bot_api_service.name
|
||||
role = "roles/run.invoker"
|
||||
member = "serviceAccount:${google_service_account.scheduler_invoker.email}"
|
||||
}
|
||||
|
||||
resource "google_service_account_iam_member" "scheduler_token_creator" {
|
||||
service_account_id = google_service_account.scheduler_invoker.name
|
||||
role = "roles/iam.serviceAccountTokenCreator"
|
||||
member = "serviceAccount:service-${data.google_project.current.number}@gcp-sa-cloudscheduler.iam.gserviceaccount.com"
|
||||
}
|
||||
|
||||
resource "google_cloud_scheduler_job" "reminders" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
name = "${local.name_prefix}-reminders"
|
||||
schedule = var.scheduler_cron
|
||||
time_zone = var.scheduler_timezone
|
||||
paused = var.scheduler_paused
|
||||
|
||||
http_target {
|
||||
uri = "${module.bot_api_service.uri}${var.scheduler_path}"
|
||||
http_method = var.scheduler_http_method
|
||||
|
||||
headers = {
|
||||
"Content-Type" = "application/json"
|
||||
}
|
||||
|
||||
body = base64encode(var.scheduler_body_json)
|
||||
|
||||
oidc_token {
|
||||
service_account_email = google_service_account.scheduler_invoker.email
|
||||
audience = module.bot_api_service.uri
|
||||
}
|
||||
}
|
||||
|
||||
depends_on = [
|
||||
module.bot_api_service,
|
||||
google_service_account_iam_member.scheduler_token_creator
|
||||
]
|
||||
}
|
||||
|
||||
resource "google_service_account" "github_deployer" {
|
||||
count = var.create_workload_identity ? 1 : 0
|
||||
|
||||
project = var.project_id
|
||||
account_id = var.github_deploy_service_account_id
|
||||
display_name = "${local.name_prefix} GitHub deployer"
|
||||
}
|
||||
|
||||
resource "google_iam_workload_identity_pool" "github" {
|
||||
count = var.create_workload_identity ? 1 : 0
|
||||
|
||||
project = var.project_id
|
||||
workload_identity_pool_id = var.workload_identity_pool_id
|
||||
display_name = "GitHub Actions Pool"
|
||||
}
|
||||
|
||||
resource "google_iam_workload_identity_pool_provider" "github" {
|
||||
count = var.create_workload_identity ? 1 : 0
|
||||
|
||||
project = var.project_id
|
||||
workload_identity_pool_id = google_iam_workload_identity_pool.github[0].workload_identity_pool_id
|
||||
workload_identity_pool_provider_id = var.workload_identity_provider_id
|
||||
display_name = "GitHub Actions Provider"
|
||||
|
||||
attribute_mapping = {
|
||||
"google.subject" = "assertion.sub"
|
||||
"attribute.actor" = "assertion.actor"
|
||||
"attribute.repository" = "assertion.repository"
|
||||
}
|
||||
|
||||
attribute_condition = "assertion.repository == \"${var.github_repository}\""
|
||||
|
||||
oidc {
|
||||
issuer_uri = "https://token.actions.githubusercontent.com"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_service_account_iam_member" "github_oidc" {
|
||||
count = var.create_workload_identity ? 1 : 0
|
||||
|
||||
service_account_id = google_service_account.github_deployer[0].name
|
||||
role = "roles/iam.workloadIdentityUser"
|
||||
member = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github[0].name}/attribute.repository/${var.github_repository}"
|
||||
}
|
||||
|
||||
resource "google_project_iam_member" "github_deployer_roles" {
|
||||
for_each = var.create_workload_identity ? local.github_deploy_roles : toset([])
|
||||
|
||||
project = var.project_id
|
||||
role = each.value
|
||||
member = "serviceAccount:${google_service_account.github_deployer[0].email}"
|
||||
}
|
||||
67
infra/terraform/modules/cloud_run_service/main.tf
Normal file
67
infra/terraform/modules/cloud_run_service/main.tf
Normal file
@@ -0,0 +1,67 @@
|
||||
resource "google_cloud_run_v2_service" "this" {
|
||||
project = var.project_id
|
||||
location = var.region
|
||||
name = var.name
|
||||
|
||||
ingress = "INGRESS_TRAFFIC_ALL"
|
||||
deletion_protection = false
|
||||
|
||||
labels = var.labels
|
||||
|
||||
template {
|
||||
service_account = var.service_account_email
|
||||
|
||||
scaling {
|
||||
min_instance_count = var.min_instance_count
|
||||
max_instance_count = var.max_instance_count
|
||||
}
|
||||
|
||||
containers {
|
||||
image = var.image
|
||||
|
||||
ports {
|
||||
container_port = var.container_port
|
||||
}
|
||||
|
||||
resources {
|
||||
limits = var.limits
|
||||
}
|
||||
|
||||
dynamic "env" {
|
||||
for_each = var.env
|
||||
content {
|
||||
name = env.key
|
||||
value = env.value
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "env" {
|
||||
for_each = var.secret_env
|
||||
content {
|
||||
name = env.key
|
||||
value_source {
|
||||
secret_key_ref {
|
||||
secret = env.value
|
||||
version = "latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traffic {
|
||||
percent = 100
|
||||
type = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_cloud_run_v2_service_iam_member" "public_invoker" {
|
||||
count = var.allow_unauthenticated ? 1 : 0
|
||||
|
||||
project = var.project_id
|
||||
location = var.region
|
||||
name = google_cloud_run_v2_service.this.name
|
||||
role = "roles/run.invoker"
|
||||
member = "allUsers"
|
||||
}
|
||||
7
infra/terraform/modules/cloud_run_service/outputs.tf
Normal file
7
infra/terraform/modules/cloud_run_service/outputs.tf
Normal file
@@ -0,0 +1,7 @@
|
||||
output "name" {
|
||||
value = google_cloud_run_v2_service.this.name
|
||||
}
|
||||
|
||||
output "uri" {
|
||||
value = google_cloud_run_v2_service.this.uri
|
||||
}
|
||||
63
infra/terraform/modules/cloud_run_service/variables.tf
Normal file
63
infra/terraform/modules/cloud_run_service/variables.tf
Normal file
@@ -0,0 +1,63 @@
|
||||
variable "project_id" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "image" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "service_account_email" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "allow_unauthenticated" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "env" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "secret_env" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "container_port" {
|
||||
type = number
|
||||
default = 8080
|
||||
}
|
||||
|
||||
variable "min_instance_count" {
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "max_instance_count" {
|
||||
type = number
|
||||
default = 3
|
||||
}
|
||||
|
||||
variable "limits" {
|
||||
type = map(string)
|
||||
default = {
|
||||
cpu = "1"
|
||||
memory = "512Mi"
|
||||
}
|
||||
}
|
||||
44
infra/terraform/outputs.tf
Normal file
44
infra/terraform/outputs.tf
Normal file
@@ -0,0 +1,44 @@
|
||||
output "artifact_repository" {
|
||||
description = "Artifact Registry repository"
|
||||
value = google_artifact_registry_repository.containers.id
|
||||
}
|
||||
|
||||
output "bot_api_service_name" {
|
||||
description = "Cloud Run bot API service name"
|
||||
value = module.bot_api_service.name
|
||||
}
|
||||
|
||||
output "bot_api_service_url" {
|
||||
description = "Cloud Run bot API URL"
|
||||
value = module.bot_api_service.uri
|
||||
}
|
||||
|
||||
output "mini_app_service_name" {
|
||||
description = "Cloud Run mini app service name"
|
||||
value = module.mini_app_service.name
|
||||
}
|
||||
|
||||
output "mini_app_service_url" {
|
||||
description = "Cloud Run mini app URL"
|
||||
value = module.mini_app_service.uri
|
||||
}
|
||||
|
||||
output "scheduler_job_name" {
|
||||
description = "Cloud Scheduler job for reminders"
|
||||
value = google_cloud_scheduler_job.reminders.name
|
||||
}
|
||||
|
||||
output "runtime_secret_ids" {
|
||||
description = "Secret Manager IDs expected by runtime"
|
||||
value = sort([for secret in google_secret_manager_secret.runtime : secret.secret_id])
|
||||
}
|
||||
|
||||
output "github_deployer_service_account" {
|
||||
description = "GitHub OIDC deployer service account email"
|
||||
value = var.create_workload_identity ? google_service_account.github_deployer[0].email : null
|
||||
}
|
||||
|
||||
output "github_workload_identity_provider" {
|
||||
description = "Full Workload Identity Provider resource name"
|
||||
value = var.create_workload_identity ? google_iam_workload_identity_pool_provider.github[0].name : null
|
||||
}
|
||||
4
infra/terraform/providers.tf
Normal file
4
infra/terraform/providers.tf
Normal file
@@ -0,0 +1,4 @@
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
}
|
||||
16
infra/terraform/terraform.tfvars.example
Normal file
16
infra/terraform/terraform.tfvars.example
Normal file
@@ -0,0 +1,16 @@
|
||||
project_id = "my-gcp-project"
|
||||
region = "europe-west1"
|
||||
environment = "dev"
|
||||
service_prefix = "household"
|
||||
|
||||
artifact_repository_id = "household-bot"
|
||||
|
||||
bot_api_image = "europe-west1-docker.pkg.dev/my-gcp-project/household-bot/bot-api:latest"
|
||||
mini_app_image = "europe-west1-docker.pkg.dev/my-gcp-project/household-bot/mini-app:latest"
|
||||
|
||||
scheduler_cron = "0 9 * * *"
|
||||
scheduler_timezone = "Asia/Tbilisi"
|
||||
scheduler_paused = true
|
||||
|
||||
create_workload_identity = true
|
||||
github_repository = "whekin/household-bot"
|
||||
167
infra/terraform/variables.tf
Normal file
167
infra/terraform/variables.tf
Normal file
@@ -0,0 +1,167 @@
|
||||
variable "project_id" {
|
||||
description = "GCP project ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "Primary GCP region for Cloud Run services"
|
||||
type = string
|
||||
default = "europe-west1"
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
description = "Environment name (e.g. dev, prod)"
|
||||
type = string
|
||||
default = "dev"
|
||||
}
|
||||
|
||||
variable "service_prefix" {
|
||||
description = "Prefix for service names"
|
||||
type = string
|
||||
default = "household"
|
||||
}
|
||||
|
||||
variable "artifact_repository_id" {
|
||||
description = "Artifact Registry repository ID"
|
||||
type = string
|
||||
default = "household-bot"
|
||||
}
|
||||
|
||||
variable "artifact_repository_location" {
|
||||
description = "Artifact Registry location (defaults to region)"
|
||||
type = string
|
||||
default = null
|
||||
nullable = true
|
||||
}
|
||||
|
||||
variable "bot_api_image" {
|
||||
description = "Container image for bot API service"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "mini_app_image" {
|
||||
description = "Container image for mini app service"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "telegram_webhook_secret_id" {
|
||||
description = "Secret Manager ID for Telegram webhook secret token"
|
||||
type = string
|
||||
default = "telegram-webhook-secret"
|
||||
}
|
||||
|
||||
variable "scheduler_shared_secret_id" {
|
||||
description = "Secret Manager ID for app-level scheduler secret"
|
||||
type = string
|
||||
default = "scheduler-shared-secret"
|
||||
}
|
||||
|
||||
variable "supabase_url_secret_id" {
|
||||
description = "Optional Secret Manager ID for SUPABASE_URL"
|
||||
type = string
|
||||
default = null
|
||||
nullable = true
|
||||
}
|
||||
|
||||
variable "supabase_publishable_key_secret_id" {
|
||||
description = "Optional Secret Manager ID for SUPABASE_PUBLISHABLE_KEY"
|
||||
type = string
|
||||
default = null
|
||||
nullable = true
|
||||
}
|
||||
|
||||
variable "scheduler_path" {
|
||||
description = "Reminder endpoint path on bot API"
|
||||
type = string
|
||||
default = "/internal/scheduler/reminders"
|
||||
}
|
||||
|
||||
variable "scheduler_http_method" {
|
||||
description = "Scheduler HTTP method"
|
||||
type = string
|
||||
default = "POST"
|
||||
}
|
||||
|
||||
variable "scheduler_cron" {
|
||||
description = "Cron expression for reminder scheduler"
|
||||
type = string
|
||||
default = "0 9 * * *"
|
||||
}
|
||||
|
||||
variable "scheduler_timezone" {
|
||||
description = "Scheduler timezone"
|
||||
type = string
|
||||
default = "Asia/Tbilisi"
|
||||
}
|
||||
|
||||
variable "scheduler_body_json" {
|
||||
description = "JSON payload for scheduler requests"
|
||||
type = string
|
||||
default = "{\"kind\":\"monthly-reminder\"}"
|
||||
}
|
||||
|
||||
variable "scheduler_paused" {
|
||||
description = "Whether scheduler should be paused initially"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "bot_min_instances" {
|
||||
description = "Minimum bot API instances"
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "bot_max_instances" {
|
||||
description = "Maximum bot API instances"
|
||||
type = number
|
||||
default = 3
|
||||
}
|
||||
|
||||
variable "mini_min_instances" {
|
||||
description = "Minimum mini app instances"
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "mini_max_instances" {
|
||||
description = "Maximum mini app instances"
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
variable "labels" {
|
||||
description = "Additional labels"
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "create_workload_identity" {
|
||||
description = "Create GitHub OIDC Workload Identity resources"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "github_repository" {
|
||||
description = "GitHub repository in owner/repo format"
|
||||
type = string
|
||||
default = "whekin/household-bot"
|
||||
}
|
||||
|
||||
variable "workload_identity_pool_id" {
|
||||
description = "Workload Identity Pool ID"
|
||||
type = string
|
||||
default = "github-pool"
|
||||
}
|
||||
|
||||
variable "workload_identity_provider_id" {
|
||||
description = "Workload Identity Provider ID"
|
||||
type = string
|
||||
default = "github-provider"
|
||||
}
|
||||
|
||||
variable "github_deploy_service_account_id" {
|
||||
description = "Service account ID used by GitHub Actions via OIDC"
|
||||
type = string
|
||||
default = "github-deployer"
|
||||
}
|
||||
10
infra/terraform/versions.tf
Normal file
10
infra/terraform/versions.tf
Normal file
@@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.8.0"
|
||||
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user