---
name: kickoff-infra-generator
description: Generates Terraform infrastructure and GitHub workflows for a new Java project. Writes files directly in the target repo.
model: fast
---

You generate all Terraform infrastructure and GitHub workflow files for a new Java/Spring Boot project. You write files directly in the target repo.

**You receive:**

- `targetRepoPath` (absolute path to the target project)
- `janusPath` (absolute path to Janus repo, for direct file copies)
- `infraTemplates` (string — Section 7 from reference-reader output: full Terraform file contents)
- `workflowTemplates` (string — Section 6 from reference-reader output: full workflow file contents)
- `copyVerbatimFiles` (string — Section 2 from reference-reader output: tflint.hcl, generate-terraform-docs.sh contents)
- `projectName` (string, e.g. `"my-service"`)
- `projectPrefix` (string, e.g. `"my-service"`)
- `githubRepo` (string, e.g. `"HumandDev/humand-my-service"`)
- `options`:
  - `kafka` (bool)
  - `ownDatabase` (bool)
  - `worker` (bool)
  - `loadBalancer` (bool)
  - `lbPriority` (number, required if loadBalancer=true)
  - `grpc` (bool)

## Substitution Rules

These substitutions apply throughout all generated files:

| Pattern | Replacement | Example |
|---------|-------------|---------|
| `janus` (in identifiers) | `{projectName}` | `janus_docker_image` → `my_service_docker_image` |
| `Janus` (in names) | `{ProjectName}` (PascalCase) | `Janus Service` → `My Service` |
| `JANUS` (in env vars) | `{PROJECT_NAME}` (UPPER_SNAKE) | `HUMAND_JANUS_*` → `HUMAND_MY_SERVICE_*` |
| `humand-janus` | `humand-{projectName}` | `humand-janus-service` → `humand-my-service-service` |
| `janus-webapp` | `{projectPrefix}-webapp` | `janus-webapp` → `my-service-webapp` |
| `/api/v1/janus/` | `/api/v1/{projectName}/` | Path patterns in LB rules |
| `co.humand.janus` | `co.humand.{basePackage}` | Java package references in Terraform |
| ECR repo name | New ECR repo name | Match the GitHub repo name pattern |

When `projectName` contains hyphens (e.g. `my-service`):
- **Terraform identifiers** (resource names, variable names): replace hyphens with underscores → `my_service`
- **HCL string values** (service names, SSM paths): keep hyphens → `my-service`
- **Environment variable names**: UPPER_SNAKE_CASE → `MY_SERVICE`

## What You Generate

### 1. Root Infrastructure Files

Create in `{targetRepoPath}/infrastructure/`:

- **`tflint.hcl`** — Extract from `copyVerbatimFiles` section, write verbatim (no substitutions)
- **`generate-terraform-docs.sh`** — Extract from `copyVerbatimFiles` section, write verbatim, make executable (`chmod +x`)

### 2. Terraform Modules

#### modules/datadog/ (4 files)

Copy directly from `{janusPath}/infrastructure/modules/datadog/`. These files are generic — no substitutions needed.

- `main.tf`
- `variables.tf`
- `outputs.tf`
- `versions.tf`

#### modules/db/ (if ownDatabase=true, 4 files)

Extract from `infraTemplates` (Section 7 db files). Apply substitutions:

- `humand-janus-db` → `humand-{projectName}-db`
- `janus_database_name` → `{project_snake}_database_name`
- `janus_master_username` → `{project_snake}_master_username`
- `janus_jooq_username` → `{project_snake}_jooq_username` (or `_hibernate_username` based on context)
- `janus_liquibase_username` → `{project_snake}_liquibase_username`
- `janus_iam_username` → `{project_snake}_iam_username`
- `janus_db_params` → `{project_snake}_db_params`
- `janus_db_connect_policy_arn` → `{project_snake}_db_connect_policy_arn`
- `humand-janus-db-connect-policy` → `humand-{projectName}-db-connect-policy`

Files: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`

#### modules/{projectName}/ (4 files)

Extract from `infraTemplates` (Section 7 janus module files). Apply all substitution rules.

Key adaptations:
- Variable names: `janus_docker_image` → `{project_snake}_docker_image`, `janus_lb_host_condition` → `{project_snake}_lb_host_condition`
- Service name: `humand-janus-service` → `humand-{projectName}-service`
- Datadog `dd_source`: `"janus"` → `"{projectName}"`
- **If kafka=false**: Remove `msk_cluster_name` variable, `aws_msk_cluster` data source, `SPRING_KAFKA_BOOTSTRAP_SERVERS` env var, `HUMAND_*_KAFKA_CDC_LISTENER_ENABLED` from `type_environments`, and any MSK IAM policy
- **If kafka=true**: Keep all Kafka-related resources but with a generic/placeholder IAM policy (specific topics added by `/add-java-kafka-cdc-consumer`)
- **If loadBalancer=false**: Remove `module "lb"` block and LB-related variables/locals
- **If worker=false**: Remove `type_environments` local that toggles Kafka listener

Files: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`

#### modules/{projectName}/modules/lb/ (if loadBalancer=true, 4 files)

Extract from `infraTemplates` (Section 7 lb files). Apply substitutions:

- `janus_tg` → `{project_snake}_tg`
- `humand-janus-tg` → `humand-{projectName}-tg`
- `janus_lb_rule` → `{project_snake}_lb_rule`
- `/api/v1/janus/*` → `/api/v1/{projectName}/*`
- `janus_lb_host_condition` → `{project_snake}_lb_host_condition`

Files: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`

#### modules/service/ (4 files)

Extract from `infraTemplates` (Section 7 service files). Apply substitutions:

- Module call names: `module "janus"` → `module "{project_snake}"`
- Module call names: `module "janus-worker"` → `module "{project_snake}-worker"` (if worker=true, remove if worker=false)
- Variable names: `janus_docker_image` → `{project_snake}_docker_image`, `janus_lb_host_condition` → `{project_snake}_lb_host_condition`
- Source paths: `"../janus"` → `"../{projectName}"`
- Service names: `humand-janus-service` → `humand-{projectName}-service`, `humand-janus-worker` → `humand-{projectName}-worker`
- DB outputs: `janus_db_params` → `{project_snake}_db_params`, `janus_db_connect_policy_arn` → `{project_snake}_db_connect_policy_arn`
- **If ownDatabase=false**: Remove `module "database"` block, DB variables, DB-related module arguments, DB outputs
- **If kafka=false**: Remove `msk_cluster_name` variable and argument
- **If worker=false**: Remove the worker module call entirely

Files: `main.tf`, `variables.tf`, `outputs.tf`, `versions.tf`

### 3. Environment Files

For each of **dev**, **stg**, **prd**, **testslot1**, **testslot2**, create 5 files in `{targetRepoPath}/infrastructure/env/{env}/`.

Use these hardcoded AWS values:

| Env | AWS Account | VPC ID | host_condition | server_domain_url |
|-----|-------------|--------|----------------|-------------------|
| dev | 923929101992 | `vpc-0ca675a5ccd7a6bcf` | `api.dev.humand.co` | `api.dev.humand.co` |
| stg | 302630094508 | `vpc-0d7fdc859a78c20d4` | `api.stg.humand.co` | `api.stg.humand.co` |
| prd | 887841176879 | `vpc-0b49d2aaa00ecc5f7` | `api-prd.humand.co` | `api-prd.humand.co` |
| testslot1 | 836513903801 | `vpc-038d4e6243997b3b6` | `api.slot1.humand.co` | `api.slot1.humand.co` |
| testslot2 | 058264267871 | `vpc-0b8cab5e160e52538` | `api.slot2.humand.co` | `api.slot2.humand.co` |

#### main.tf

```hcl
data "aws_ecs_cluster" "public_cluster" {
  cluster_name = "public-{env}-services"
}

data "aws_ecs_cluster" "private_cluster" {
  cluster_name = "private-{env}-services"
}

module "service" {
  source = "../../modules/service"

  aws_account       = "{AWS_ACCOUNT}"
  env               = "{env}"
  server_domain_url = "{SERVER_DOMAIN_URL}"
  humand_vpc_id     = "{VPC_ID}"

  ecs_public_cluster_arn  = data.aws_ecs_cluster.public_cluster.arn
  ecs_private_cluster_arn = data.aws_ecs_cluster.private_cluster.arn

  {project_snake}_docker_image      = var.docker_image
  commit_sha                        = var.commit_sha
  logging_http_log_body             = false
  {project_snake}_lb_host_condition = "{HOST_CONDITION}"
}
```

Conditional additions to `module "service"`:
- **If kafka=true**: add `msk_cluster_name = "humand-aws-msk-cluster"`
- **If ownDatabase=true**: add `subnet_group_name`, `db_instance_class`, `db_backup_retention_period` (use `db.t4g.medium`, retention=1 for non-prd, 7 for prd)

ECS cluster naming: `public-{env}-services` and `private-{env}-services`.

Note: `prd` uses `api-prd.humand.co` (hyphen, not dot).

#### providers.tf

```hcl
provider "aws" {
  region = "us-east-1"
  default_tags {
    tags = {
      Environment = "{env}"
      Name        = "humand-{projectName}"
      Terraform   = "true"
      Repository  = "humand-{projectName}-service"
    }
  }
}

provider "null" {}
```

#### variables.tf

```hcl
variable "docker_image" {
  description = "Docker image to deploy"
  type        = string
}

variable "commit_sha" {
  description = "The commit SHA for Datadog version tagging"
  type        = string
  default     = "local"
}
```

#### versions.tf

```hcl
terraform {
  required_version = ">= 1.5.7, < 2.0.0"

  required_providers {
    aws  = { source = "hashicorp/aws"; version = "~> 5.0" }
    null = { source = "hashicorp/null"; version = "~> 3.0" }
  }

  backend "s3" {
    bucket         = "humand-terraform-state-{env}"
    key            = "service/humand-{projectName}-service/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "humand-terraform-locks-{env}"
    encrypt        = true
  }
}
```

#### outputs.tf

```hcl
# If ownDatabase=true:
output "db_cluster_endpoint" {
  value = module.service.db_cluster_endpoint
}
```

If ownDatabase=false, create an empty `outputs.tf` (no outputs).

### 4. GitHub Workflows

Create in `{targetRepoPath}/.github/workflows/`.

Extract each workflow from `workflowTemplates`. Apply substitutions:

- `humand-janus` → `humand-{projectName}`
- `janus-webapp` → `{projectPrefix}-webapp`
- ECR repository name: match the new project repo pattern
- Service names in deployment configs

Files to create:
1. `ci.yml`
2. `ci-infra.yml`
3. `ci-terraform-init.yml`
4. `deployment.yml`
5. `dev.yml`
6. `stg.yml`
7. `prd.yml`
8. `testslot1.yml`
9. `testslot2.yml`

**If grpc=true**, also create `publish-libs.yml`.

### 5. Post-Generation

After all files are written:

1. Run `terraform fmt -recursive` from `{targetRepoPath}/infrastructure/`
2. Run `chmod +x {targetRepoPath}/infrastructure/generate-terraform-docs.sh`
3. Run `chmod +x {targetRepoPath}/mvnw` (if it exists at the target path)

## Return Format

Return a structured report:

1. **Files created** — list of all files written (relative paths from target repo root)
2. **Substitutions applied** — summary of key substitutions made (project name, variable names, service names)
3. **Conditional decisions** — what was included/excluded based on options (kafka, ownDatabase, worker, loadBalancer, grpc)
4. **Warnings** — any issues found (missing template content, files that couldn't be generated, values that need manual review)
