This document covers everything from zero to a fully running production system.
All commands are for Windows Command Prompt (CMD). Open CMD by pressing Win + R, type cmd, press Enter.
Follow every step in exact order. Do not skip anything.
| Phase | Status |
|---|---|
| Phase 1 — Accounts | DONE |
| Phase 2 — Install Tools | DONE |
| Phase 3 — AWS Account Setup | DONE |
| Phase 4 — GitHub Repository Setup | DONE |
| Phase 5 — Create GitHub App | DONE |
| Phase 6 — LangFuse Setup | DONE |
| Phase 7 — OpenAI API Key | DONE |
| Phase 8 — Provision AWS Infrastructure | DONE |
| Phase 9 — Configure GitHub Secrets | DONE |
| Phase 10 — First Deployment via GitHub Actions | DONE |
| Phase 11 — Connect kubectl to EKS | DONE |
| Phase 12 — Apply Kubernetes Manifests | DONE |
| Phase 13 — Set Up Grafana and Prometheus | DONE |
| Phase 14 — Set Up LangFuse Tracing | DONE |
| Phase 15 — Update GitHub App Webhook URL | DONE |
| Phase 16 — End-to-End Test | DONE |
- What This System Does
- Architecture Overview
- Your Machine Requirements
- Phase 1 — Accounts You Need
- Phase 2 — Install Tools on Your Windows Machine
- Phase 3 — AWS Account Setup
- Phase 4 — GitHub Repository Setup
- Phase 5 — Create GitHub App
- Phase 6 — LangFuse Setup
- Phase 7 — OpenAI API Key
- Phase 8 — Provision AWS Infrastructure with Terraform
- Phase 9 — Configure GitHub Secrets
- Phase 10 — First Deployment via GitHub Actions
- Phase 11 — Connect kubectl to EKS
- Phase 12 — Apply Kubernetes Manifests
- Phase 13 — Set Up Grafana and Prometheus
- Phase 14 — Set Up LangFuse Tracing
- Phase 15 — Update GitHub App Webhook URL
- Phase 16 — End-to-End Test
- Accessing All Dashboards and UIs
- How the Weekly Evaluation Works
- How to Check If Everything is Running
- Troubleshooting
- Cost Estimate
- Teardown — Complete Cleanup
When a developer opens a Pull Request on any GitHub repository where your GitHub App is installed:
- GitHub sends a webhook event to your system
- The gateway service verifies the request is genuinely from GitHub
- The webhook service stores the PR in your database and queues an analysis job
- The orchestrator service fetches the actual code diff from GitHub
- Four AI agents run in parallel and analyze the code for:
- Static analysis issues (complexity, unused variables, bad naming)
- Security vulnerabilities (OWASP Top 10, hardcoded secrets, SQL injection)
- Style issues (formatting, readability)
- Architecture issues (separation of concerns, missing error handling)
- The reviewer service posts the findings as inline comments directly on the GitHub PR
- When the PR is merged, the learner service stores the patterns to improve future reviews
Internet
|
v
AWS Load Balancer (public IP)
|
v
gateway service (port 8000) <- verifies GitHub HMAC signature
|
v
webhook service (port 8001) <- parses event, writes to RDS PostgreSQL
|
v
Celery Worker (Redis broker) <- runs background tasks
|
v
orchestrator service (port 8002) <- calls GitHub API, runs LangGraph AI agents
|
+-- static analysis agent -+
+-- security agent +-- run in parallel via LangGraph
+-- style agent |
+-- architecture agent -+
|
v
reviewer service (port 8003) <- posts comments to GitHub PR
|
v
[on merge] learner (port 8004) <- stores patterns in PostgreSQL
Infrastructure:
- EKS (Kubernetes) runs all services
- RDS PostgreSQL 15 stores PRs, findings, patterns
- ElastiCache Redis Celery task queue
- ECR stores Docker images
- S3 report storage
- LangFuse AI call tracing and observability
- Prometheus + Grafana metrics and dashboards
You run deployment commands from your local Windows machine. The actual application runs entirely on AWS — your machine only needs to run CLI tools.
What your machine needs:
- Windows 10 or Windows 11
- 4 GB RAM minimum (8 GB recommended)
- 5 GB free disk space
- Stable internet connection
Your machine never builds Docker images or runs the application. GitHub Actions (running on GitHub's servers) handles all that. Your CMD terminal is only used to run Terraform, kubectl, AWS CLI, and Git commands.
What runs on AWS (not on your machine):
- All 5 services run as pods on EKS nodes (t3.medium — 2 vCPU, 4 GB RAM each, 2 nodes)
- PostgreSQL runs on RDS
- Redis runs on ElastiCache
Create all these accounts before doing anything else.
- Go to https://aws.amazon.com
- Click "Create an AWS Account"
- Enter your email, a password, and an account name
- Enter your credit card (you will be charged for what you use — see the cost estimate at the end)
- Complete phone verification
- Choose "Basic support" (free)
- Log in to the AWS Console at https://console.aws.amazon.com
- Go to https://github.com
- Sign up if you do not have an account
- Verify your email address
- Go to https://platform.openai.com
- Sign up with your email
- Go to Billing and add a payment method
- Add at least $10 of credits — this is needed to call GPT-4o-mini
- Go to Billing → Usage limits and set a monthly limit of $20 to avoid surprises
LangFuse records every single OpenAI API call your system makes. You can see what prompt was sent, what came back, how many tokens were used, and what it cost. It is free.
- Go to https://langfuse.com
- Click "Get Started Free"
- Sign up with GitHub or email
- After signing in, create a new project — name it
ai-code-reviewer - Go to Settings in the left sidebar
- Click "API Keys"
- Click "Create new API key"
- Copy and save both keys:
- Public Key (starts with
pk-lf-) — you will need this later - Secret Key (starts with
sk-lf-) — you will need this later
- Public Key (starts with
Open CMD as Administrator for all install steps. To open CMD as Administrator:
Press Win, type cmd, right-click "Command Prompt", click "Run as administrator".
- Open your browser and go to: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-windows.html
- Click the link to download the Windows installer (
AWSCLIV2.msi) - Double-click the downloaded file and run the installer
- Keep all default settings and click through to finish
- Close and reopen CMD
- Run this to verify:
You should see:
aws --versionaws-cli/2.x.x Python/3.x.x Windows/...
- Go to https://developer.hashicorp.com/terraform/install
- Under Windows, click "AMD64" to download the zip file
- Open the downloaded zip file
- Extract
terraform.exefrom the zip - Move
terraform.exetoC:\Windows\System32\(This makes theterraformcommand available from any folder in CMD) - Close and reopen CMD
- Run this to verify:
You should see:
terraform --versionTerraform v1.x.x
- Go to https://kubernetes.io/docs/tasks/tools/install-kubectl-windows/
- Download the latest
kubectl.exebinary (there is a direct download link on that page) - Move
kubectl.exetoC:\Windows\System32\ - Close and reopen CMD
- Run this to verify:
You should see a version number printed
kubectl version --client
- Go to https://git-scm.com/download/win
- Download the installer (64-bit)
- Run the installer — keep all default settings
- Click through to finish
- Close and reopen CMD
- Run this to verify:
You should see:
git --versiongit version 2.x.x.windows.x
Helm is needed to install Prometheus and Grafana on your Kubernetes cluster.
- Go to https://helm.sh/docs/intro/install/
- Under "From the Binary Releases" section, click the link for Windows
- Download the zip for windows-amd64
- Extract
helm.exefrom the zip - Move
helm.exetoC:\Windows\System32\ - Close and reopen CMD
- Run this to verify:
helm version
Open a fresh CMD window and run all five commands. All must show a version number:
aws --version
terraform --version
kubectl version --client
git --version
helm version
If any of these fails, go back to that tool's step and reinstall it.
- Go to https://console.aws.amazon.com
- In the search bar at the top type
IAMand click on IAM - In the left sidebar click "Users"
- Click "Create user"
- Username:
ai-reviewer-deployer - Click Next
- Select "Attach policies directly"
- In the search box type
AdministratorAccess - Check the box next to
AdministratorAccess - Click Next
- Click "Create user"
- Click on the user
ai-reviewer-deployerthat you just created - Click the "Security credentials" tab
- Scroll down to "Access keys" and click "Create access key"
- Select "Command Line Interface (CLI)"
- Check the confirmation checkbox at the bottom
- Click Next, then "Create access key"
- You will now see the Access Key ID and Secret Access Key
- IMPORTANT: Copy both values right now into a Notepad file. Once you close this page, you can never see the Secret Access Key again.
Open CMD and run:
aws configure
It will ask four questions. Answer them exactly like this:
AWS Access Key ID [None]: paste your Access Key ID here and press Enter
AWS Secret Access Key [None]: paste your Secret Access Key here and press Enter
Default region name [None]: us-east-1
Default output format [None]: json
Now verify it works:
aws sts get-caller-identity
You should see a response with your account ID and user ARN. If you see an error, your credentials are wrong — go back to step 6.1 and create new access keys.
Run this command:
aws sts get-caller-identity --query Account --output text
This prints a 12-digit number like 123456789012. Save this number — it is your AWS_ACCOUNT_ID. You will need it in later steps.
This allows GitHub Actions to deploy to AWS without storing long-lived AWS keys in GitHub. It is the secure, recommended way.
- Go to AWS Console → IAM
- In the left sidebar click "Identity providers"
- Click "Add provider"
- Provider type: select "OpenID Connect"
- Provider URL:
https://token.actions.githubusercontent.com - Click "Get thumbprint" — it will auto-fill
- Audience:
sts.amazonaws.com - Click "Add provider"
- Go to IAM → Roles → "Create role"
- Trusted entity type: select "Web identity"
- Identity provider: select
token.actions.githubusercontent.com - Audience: select
sts.amazonaws.com - Click Next
- You need to add a condition. Scroll down and click "Add condition":
- Condition operator:
StringLike - Condition key:
token.actions.githubusercontent.com:sub - Value:
repo:YOUR_GITHUB_USERNAME/ai-code-reviewer:*(Replace YOUR_GITHUB_USERNAME with your actual GitHub username — for examplerepo:johnsmith/ai-code-reviewer:*)
- Condition operator:
- Click Next
- In the search box type
AdministratorAccessand check it - Click Next
- Role name:
github-actions-ai-reviewer - Click "Create role"
- Click on the role
github-actions-ai-reviewerthat you just created - Copy the Role ARN at the top — it looks like:
arn:aws:iam::123456789012:role/github-actions-ai-reviewer - Save this. It is your
AWS_ROLE_ARN.
- Go to https://github.com
- Click the "+" icon in the top right → "New repository"
- Repository name:
ai-code-reviewer - Visibility: Private
- Do NOT check "Add a README file"
- Click "Create repository"
- Go to GitHub → click your profile picture → Settings
- Scroll all the way down in the left sidebar → "Developer settings"
- Click "Personal access tokens" → "Tokens (classic)"
- Click "Generate new token" → "Generate new token (classic)"
- Note (name):
ai-code-reviewer-push - Expiration: 90 days
- Check these scopes:
repoandworkflow - Click "Generate token"
- Copy the token — it starts with
ghp_... - Save it. You will use this as your password when Git asks.
Open CMD and run these commands one by one:
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer"
git init
git add .
git commit -m "initial: full project setup"
git branch -M main
git remote add origin https://github.com/YOUR_USERNAME/ai-code-reviewer.git
git push -u origin main
When CMD asks for your GitHub username, enter your GitHub username. When it asks for your password, paste the Personal Access Token you created in step 7.2 (not your GitHub account password).
After this completes, go to https://github.com/YOUR_USERNAME/ai-code-reviewer and you should see all the project files there.
The GitHub App is the identity your bot uses to read PR diffs and post review comments on GitHub.
- Go to GitHub → click your profile picture → Settings
- Scroll down in the left sidebar → "Developer settings"
- Click "GitHub Apps"
- Click "New GitHub App"
Fill in each field:
- GitHub App name:
ai-code-reviewer-bot(This name must be globally unique across all of GitHub. If it is taken, add numbers likeai-code-reviewer-bot-2024) - Homepage URL:
https://github.com/YOUR_USERNAME/ai-code-reviewer - Webhook section — make sure "Active" is checked
- Webhook URL:
https://placeholder.com(You will replace this with the real URL in Phase 15 after deployment) - Webhook secret: Type a long random string. Example:
myWebhookSecret_abc123XYZ789Write this down — it is yourGITHUB_WEBHOOK_SECRET. You need it later.
Scroll down to "Repository permissions". Change these two:
- Contents: Read-only
- Pull requests: Read and write
Leave everything else as "No access".
Scroll down to "Subscribe to events". Check this box:
- Pull request
Select "Any account" so you can install it on any of your repositories.
- Click "Create GitHub App" at the bottom
- You are now on the app's settings page
- Look for App ID near the top — it is a number like
12345678Save this. It is yourGITHUB_APP_ID. - Scroll down to the "Private keys" section
- Click "Generate a private key"
- A
.pemfile will automatically download to your Downloads folder - Open that
.pemfile with Notepad:- Go to your Downloads folder
- Right-click the
.pemfile → Open with → Notepad
- The file contains text starting with
-----BEGIN RSA PRIVATE KEY----- - Press Ctrl+A to select all, then Ctrl+C to copy
- Save this somewhere safe — it is your
GITHUB_APP_PRIVATE_KEY
- On the GitHub App page, look for "Install App" in the left sidebar and click it
- You will see your GitHub account listed — click "Install"
- Select "Only select repositories"
- Choose the repository
ai-code-reviewer(and any other repos you want the bot to review) - Click "Install"
LangFuse is already wired into the orchestrator service code. No code changes needed — you just need your API keys.
- Go to https://cloud.langfuse.com and log in
- Click on your
ai-code-reviewerproject - Click "Settings" in the left sidebar
- Click "API Keys"
- Click "Create new API key"
- Copy and save both:
- Public Key — starts with
pk-lf-— this isLANGFUSE_PUBLIC_KEY - Secret Key — starts with
sk-lf-— this isLANGFUSE_SECRET_KEY
- Public Key — starts with
- Go to https://platform.openai.com
- Click your profile icon in the top right → "API keys"
- Click "Create new secret key"
- Name:
ai-code-reviewer - Click "Create secret key"
- Copy the key — it starts with
sk-proj-...orsk-... - Save it. This is your
OPENAI_API_KEY.
This step creates all the AWS resources your system needs: the Kubernetes cluster, database, Redis, container registry, and storage. You only do this once.
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\terraform"
terraform init
This downloads all required providers and modules from the internet. You will see a lot of output. It finishes with:
Terraform has been successfully initialized!
If you see errors, check your internet connection and that you are in the correct folder.
terraform plan -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!" -var="environment=production"
Read through the output. It will show everything it plans to create:
- 1 VPC (virtual network on AWS)
- 1 EKS cluster with 2 worker nodes
- 1 RDS PostgreSQL database
- 1 ElastiCache Redis cluster
- 1 S3 bucket
- 5 ECR repositories (one per service)
If there are errors, check your AWS credentials:
aws sts get-caller-identity
terraform apply -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!" -var="environment=production"
Terraform will show the plan again and ask:
Do you want to perform these actions? Enter a value:
Type yes and press Enter.
This takes 15 to 25 minutes. The EKS cluster takes the longest to create. Leave CMD open and wait.
You will see lines like:
aws_vpc.main: Creating...
aws_eks_cluster.main: Creating...
aws_db_instance.postgres: Creating...
When it finishes you will see:
Apply complete! Resources: XX added, 0 changed, 0 destroyed.
terraform output
Copy every line of the output and save it in a text file. It will look like:
eks_cluster_endpoint = "https://XXXXX.gr7.us-east-1.eks.amazonaws.com"
rds_endpoint = "ai-code-reviewer-postgres.XXXX.us-east-1.rds.amazonaws.com:5432"
redis_endpoint = "ai-code-reviewer-redis.XXXX.cache.amazonaws.com:6379"
ecr_gateway_url = "123456789012.dkr.ecr.us-east-1.amazonaws.com/gateway"
ecr_webhook_url = "123456789012.dkr.ecr.us-east-1.amazonaws.com/webhook"
ecr_orchestrator_url = "123456789012.dkr.ecr.us-east-1.amazonaws.com/orchestrator"
ecr_reviewer_url = "123456789012.dkr.ecr.us-east-1.amazonaws.com/reviewer"
ecr_learner_url = "123456789012.dkr.ecr.us-east-1.amazonaws.com/learner"
You will use these values in the next steps.
These secrets are used by GitHub Actions when it automatically builds and deploys your code. You add them once and they are stored securely by GitHub.
- Go to https://github.com/YOUR_USERNAME/ai-code-reviewer
- Click "Settings" (the tab at the top of the repo page)
- In the left sidebar click "Secrets and variables"
- Click "Actions"
- Click "New repository secret"
For each secret: click "New repository secret", enter the Name and Value, click "Add secret".
AWS secrets — add these 3:
| Name | Value |
|---|---|
AWS_ACCOUNT_ID |
your 12-digit number from Step 6.3 |
AWS_ROLE_ARN |
the full ARN from Step 6.5 — looks like arn:aws:iam::123456789012:role/github-actions-ai-reviewer |
EKS_CLUSTER_NAME |
ai-code-reviewer |
After adding all secrets, you should have 3 secrets total: AWS_ACCOUNT_ID, AWS_ROLE_ARN, EKS_CLUSTER_NAME.
Note —
OPENAI_API_KEYandDATABASE_URLdo NOT go here: The evaluate job runs inside the Kubernetes cluster and reads these values directly frominfra/k8s/secret.yamlat runtime. They do not need to be GitHub Actions secrets.
Important — what does NOT go here:
LANGFUSE_PUBLIC_KEYandLANGFUSE_SECRET_KEYare NOT GitHub Actions secrets. No pipeline uses them. They go only intoinfra/k8s/secret.yamlin Phase 12 so Kubernetes pods can read them at runtime.GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY,GITHUB_WEBHOOK_SECRETalso go only intosecret.yaml— GitHub blocks secrets starting withGITHUB_in Actions.- The pipelines only build Docker images and run
kubectl set image. They never create or update the Kubernetes secret. That is done once manually in Phase 12.
IMPORTANT: When you run the pipelines right now, only test and build-and-push jobs will succeed. The deploy job will fail with "deployment not found" — this is expected and normal. The deploy job requires Kubernetes deployments to already exist, which only happens after you complete Phase 12. Once you finish Phase 12, re-run the pipelines and all 3 jobs will pass.
This project uses 5 separate pipelines — one per service. Each pipeline is independent:
| Pipeline file | Triggers when you change |
|---|---|
gateway.yml |
anything inside services/gateway/ |
webhook.yml |
anything inside services/webhook/ |
orchestrator.yml |
anything inside services/orchestrator/ |
reviewer.yml |
anything inside services/reviewer/ |
learner.yml |
anything inside services/learner/ |
This means if you fix a bug in the orchestrator, only the orchestrator pipeline runs — the other 4 services are untouched. Each pipeline has the same 3 jobs: test → build-and-push → deploy.
Because this is the first time, you need to trigger all 5 pipelines at once. The easiest way is to touch a file in each service:
Open CMD:
for %s in (gateway webhook orchestrator reviewer learner) do echo 6666 > services\%s\deploy.txt
git add services/
git commit -m "deploy: trigger initial deployment for all services"
git push origin main
This push touches all service directories so all 5 pipelines trigger simultaneously.
- Go to https://github.com/data-guru0/MAJOR-PROJECT-KRISH-SIR
- Click the "Actions" tab at the top
- You will see 5 separate workflow runs all starting at the same time — one per service
- Click on any of them to watch it
Each workflow has three jobs in sequence:
Job 1 — test (1-2 minutes)
- Sets up Python 3.11
- Installs pip packages for that service only
- Runs pytest for that service only
Job 2 — build-and-push (3-5 minutes)
- Logs in to your AWS ECR
- Builds the Docker image for that service only
- Pushes it to ECR tagged with the git commit SHA
Job 3 — deploy (1 minute)
- Connects to your EKS cluster
- Runs
kubectl set imagefor that service only
All three jobs in all 5 workflows must show a green checkmark.
If any job fails, click on it, then click on the failed step to read the error message.
After you finish Phase 12 (applying all Kubernetes manifests), you must re-run all 5 pipelines so the deploy job can execute successfully. The deploy job requires the Kubernetes deployments to already exist.
Each service folder has a deploy.txt file specifically for this purpose. Increment the number inside it to trigger pipelines without touching any actual code:
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer"
for %s in (gateway webhook orchestrator reviewer learner) do echo 6666 > services\%s\deploy.txt
git add services\
git commit -m "deploy: trigger all 5 pipelines after k8s setup"
git push origin main
Next time you need to trigger again, use echo 3 >, then echo 4 >, etc.
Go to GitHub → Actions tab and wait for all 3 jobs (test → build-and-push → deploy) in all 5 pipelines to show green checkmarks.
When you change only one service, only that service's pipeline runs automatically. For example, if you edit services/orchestrator/graph.py:
git add services/orchestrator/graph.py
git commit -m "fix: improve security agent prompt"
git push origin main
Only the Orchestrator CI/CD pipeline runs. The other 4 services are not touched.
kubectl is the command-line tool for managing your Kubernetes cluster. You need to configure it to talk to your EKS cluster on AWS.
Open CMD and run:
aws eks update-kubeconfig --name ai-code-reviewer --region us-east-1
You will see:
Added new context arn:aws:eks:us-east-1:123456789012:cluster/ai-code-reviewer to C:\Users\YourName\.kube\config
This creates a config file on your machine that kubectl uses to connect to AWS.
kubectl get nodes
You should see two nodes with STATUS = Ready:
NAME STATUS ROLES AGE VERSION
ip-10-0-1-xxx.ec2.internal Ready <none> 5m v1.29.x
ip-10-0-2-xxx.ec2.internal Ready <none> 5m v1.29.x
If they show NotReady, wait 3 minutes and run the command again. EKS nodes take a few minutes to fully start.
If you see "no server found" or connection refused, your aws configure credentials may be wrong. Run aws sts get-caller-identity to check.
This deploys all your services onto the EKS cluster.
Why this matters: The configmap.yaml file has a placeholder Redis URL. If you skip this step, all services will fail to connect to Redis (ElastiCache) and the entire system will return 500 errors silently.
First get your Redis endpoint from Terraform:
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\terraform"
terraform output
Copy the redis_endpoint value. It looks like:
ai-code-reviewer-redis.khmhzg.0001.use1.cache.amazonaws.com:6379
Now open the ConfigMap file:
notepad "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\k8s\configmap.yaml"
Find this line:
REDIS_URL: "redis://redis:6379/0"
Replace it with your actual endpoint (remove the :6379 from the endpoint since it's already in the URL):
REDIS_URL: "redis://YOUR_REDIS_ENDPOINT:6379/0"
Example:
REDIS_URL: "redis://ai-code-reviewer-redis.khmhzg.0001.use1.cache.amazonaws.com:6379/0"
Save the file.
You need to open and edit infra\k8s\secret.yaml with your actual secret values.
Open CMD:
notepad "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\k8s\secret.yaml"
Replace all the empty values with your real values. The file should look like this when done:
# Fill in all values before applying with: kubectl apply -f secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
stringData:
GITHUB_WEBHOOK_SECRET: "myWebhookSecret_abc123XYZ789"
GITHUB_APP_ID: "12345678"
GITHUB_APP_PRIVATE_KEY: |
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1234...
(all lines of your private key go here, keeping the line breaks)
-----END RSA PRIVATE KEY-----
OPENAI_API_KEY: "sk-proj-abc123..."
LANGFUSE_PUBLIC_KEY: "pk-lf-abc123..."
LANGFUSE_SECRET_KEY: "sk-lf-abc123..."
DATABASE_URL: "postgresql+asyncpg://dbadmin:YourStrongPassword123!@ai-code-reviewer-postgres.abc123.us-east-1.rds.amazonaws.com/codereviewer"Important notes:
- The
DATABASE_URLhere must usepostgresql+asyncpg://(with asyncpg) — this is different from the one you put in GitHub secrets - The private key must keep all its line breaks exactly as they are in the
.pemfile LANGFUSE_PUBLIC_KEYandLANGFUSE_SECRET_KEYgo here only — do NOT add them to GitHub Actions secrets. The pipeline never touches this file. These keys are read directly by the orchestrator pod at runtime.- Save the file: Ctrl+S, then close Notepad
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\k8s"
Run each command. Wait for each one to complete before running the next.
Step 1 — Apply the ConfigMap (non-secret environment variables):
kubectl apply -f configmap.yaml
Expected output: configmap/app-config created
Step 2 — Apply the Secrets:
kubectl apply -f secret.yaml
Expected output: secret/app-secrets created
Step 3 — Run the database migration:
The migration-job.yaml always uses the latest tag which is automatically pushed by the webhook pipeline on every deployment. No manual changes needed.
Just apply it directly:
kubectl apply -f migration-job.yaml
Expected output: job.batch/db-migrate created
Now wait for the migration to finish — this creates all the tables in your RDS database:
kubectl wait --for=condition=complete job/db-migrate --timeout=120s
Expected output: job.batch/db-migrate condition met
If it times out, check what happened:
kubectl logs job/db-migrate
Step 4 — Deploy all 5 services:
kubectl apply -f gateway.yaml
kubectl apply -f webhook.yaml
kubectl apply -f orchestrator.yaml
kubectl apply -f reviewer.yaml
kubectl apply -f learner.yaml
Step 5 — Deploy the Celery workers:
kubectl apply -f webhook-worker.yaml
kubectl apply -f learner-worker.yaml
Step 6 — Apply the autoscaler for orchestrator:
kubectl apply -f hpa.yaml
Step 7 — Install AWS Load Balancer Controller (required for ingress):
This controller is what creates the AWS ALB from your ingress definition. Without it the ingress will have no ADDRESS forever.
helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=ai-code-reviewer --set serviceAccount.create=true
Wait 2 minutes for the controller to start:
kubectl get pods -n kube-system
All pods should show Running.
Step 8 — Apply the ingress (creates your public URL):
kubectl apply -f ingress.yaml
kubectl get pods
Wait 3-5 minutes for all pods to start. Run this command multiple times until all show Running:
NAME READY STATUS RESTARTS AGE
gateway-7d4f9b-xxx 1/1 Running 0 3m
gateway-7d4f9b-yyy 1/1 Running 0 3m
webhook-6c8d7b-xxx 1/1 Running 0 3m
webhook-6c8d7b-yyy 1/1 Running 0 3m
webhook-worker-5f6g7h-xxx 1/1 Running 0 2m
orchestrator-9h2j3k-xxx 1/1 Running 0 3m
orchestrator-9h2j3k-yyy 1/1 Running 0 3m
reviewer-4l5m6n-xxx 1/1 Running 0 3m
reviewer-4l5m6n-yyy 1/1 Running 0 3m
learner-7p8q9r-xxx 1/1 Running 0 3m
learner-7p8q9r-yyy 1/1 Running 0 3m
learner-worker-2s3t4u-xxx 1/1 Running 0 2m
If any pod shows CrashLoopBackOff or Error, see the Troubleshooting section at the end.
kubectl get ingress gateway-ingress
Run this every minute for about 3 minutes. When the ADDRESS column shows a value, your system is live:
NAME CLASS HOSTS ADDRESS PORTS
gateway-ingress alb * k8s-default-gateway-abc123.us-east-1.elb.amazonaws.com 80,443
Copy the ADDRESS value and save it. This is your system's public URL.
Your full webhook endpoint is: https://ADDRESS/webhook/github
Note: If ADDRESS is empty, wait 3-5 minutes and run the command again. The ALB takes time to provision.
Grafana is the dashboard UI. Prometheus is what collects metrics from your services. You install both on your EKS cluster using Helm.
Open CMD and run:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
Prometheus needs persistent storage. EKS requires the EBS CSI driver to provision EBS volumes for pods.
Step 1 — Get your node group role name:
aws eks list-nodegroups --cluster-name ai-code-reviewer --region us-east-1
aws eks describe-nodegroup --cluster-name ai-code-reviewer --nodegroup-name YOUR_NODEGROUP_NAME --region us-east-1
Look for the nodeRole field — copy just the role name after the last /. It looks like default-eks-node-group-XXXXXXXXXXXX.
Step 2 — Attach the EBS CSI policy to the node group role:
Windows CMD:
aws iam attach-role-policy ^
--role-name YOUR_NODE_ROLE_NAME ^
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
Mac/Linux:
aws iam attach-role-policy \
--role-name YOUR_NODE_ROLE_NAME \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy
Step 3 — Install the EBS CSI driver addon:
aws eks create-addon --cluster-name ai-code-reviewer --addon-name aws-ebs-csi-driver --region us-east-1
Step 4 — Wait until it shows ACTIVE:
aws eks describe-addon --cluster-name ai-code-reviewer --addon-name aws-ebs-csi-driver --region us-east-1 --query addon.status --output text
Run Step 4 every minute until it shows ACTIVE before proceeding.
Wait until output shows "ACTIVE" before proceeding.
Windows CMD:
helm install prometheus prometheus-community/prometheus ^
--namespace monitoring --create-namespace ^
--set server.persistentVolume.size=8Gi ^
--set server.persistentVolume.storageClass=gp2 ^
--set alertmanager.persistence.storageClass=gp2
Mac/Linux:
helm install prometheus prometheus-community/prometheus \
--namespace monitoring --create-namespace \
--set server.persistentVolume.size=8Gi \
--set server.persistentVolume.storageClass=gp2 \
--set alertmanager.persistence.storageClass=gp2
This installs Prometheus in a new namespace called monitoring. Wait about 2 minutes.
Check that it is running:
kubectl get pods -n monitoring
All pods should show Running. It may take a few minutes.
Your project already has a config file that tells Prometheus where to find all 5 services. Apply it:
kubectl create configmap prometheus-config --from-file=prometheus.yml="D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\monitoring\prometheus.yml" -n monitoring --dry-run=client -o yaml | kubectl apply -f -
Grafana needs NLB annotations so the AWS Load Balancer Controller assigns it a public IP. Without these annotations the EXTERNAL-IP stays <pending> forever.
If Grafana is already installed from a previous attempt, uninstall it first:
helm uninstall grafana -n monitoring
Windows CMD:
helm install grafana grafana/grafana ^
--namespace monitoring ^
--set persistence.enabled=true ^
--set persistence.size=5Gi ^
--set persistence.storageClassName=gp2 ^
--set service.type=LoadBalancer ^
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-type=external" ^
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type=ip" ^
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-scheme=internet-facing"
Mac/Linux:
helm install grafana grafana/grafana \
--namespace monitoring \
--set persistence.enabled=true \
--set persistence.size=5Gi \
--set persistence.storageClassName=gp2 \
--set service.type=LoadBalancer \
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-type=external" \
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-nlb-target-type=ip" \
--set "service.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-scheme=internet-facing"
Wait 2-3 minutes then check:
kubectl get svc grafana -n monitoring
The EXTERNAL-IP column shows a URL when the NLB is ready.
Run this command — it will print the password in your CMD window:
kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" > %TEMP%\grafana_pass.txt && certutil -decode %TEMP%\grafana_pass.txt %TEMP%\grafana_pass_decoded.txt && type %TEMP%\grafana_pass_decoded.txt
If that command is complex, use this simpler alternative — install Git Bash and run:
kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode
Save the password that gets printed. The username is always admin.
kubectl get svc -n monitoring grafana
Wait 2-3 minutes. The EXTERNAL-IP column will show a URL like xxx.us-east-1.elb.amazonaws.com.
Open your browser and go to: http://EXTERNAL-IP
- Open the Grafana URL in Chrome or any browser
- You will see a login page
- Username:
admin - Password: the one you got in step 16.5
- You will be asked to change your password — set a new one and save it
- In Grafana, look at the left sidebar and click the gear icon (Configuration)
- Click "Data sources"
- Click "Add data source"
- Click "Prometheus"
- In the URL field enter:
http://prometheus-server.monitoring.svc.cluster.local - Scroll down and click "Save & Test"
- You should see a green message: "Data source is working"
Your project already has a complete Grafana dashboard saved as a JSON file.
- In Grafana, click the "+" icon in the left sidebar
- Click "Import"
- Click "Upload JSON file"
- Navigate to
D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\monitoring\grafana-dashboard.json - Select the Prometheus data source you just added
- Click "Import"
You now have a live dashboard showing 5 sections — one for each service. Each section has three panels:
- Request Rate — how many HTTP requests per minute each service is receiving
- p99 Latency — the response time for the slowest 1% of requests (tells you if something is slow)
- Error Rate — how many 5xx errors per minute (tells you if something is broken)
The dashboard updates automatically every 30 seconds.
LangFuse is already wired into the orchestrator code. You need to point it at the correct host and make sure the keys in the Kubernetes secret are valid.
LangFuse has two regions. Log in at https://langfuse.com and check the URL your browser shows after login:
cloud.langfuse.com→ you are on the EU regionus.cloud.langfuse.com→ you are on the US region
Open infra/k8s/configmap.yaml and set LANGFUSE_HOST to match your region:
EU:
LANGFUSE_HOST: "https://cloud.langfuse.com"US:
LANGFUSE_HOST: "https://us.cloud.langfuse.com"Save the file, then apply it and restart the orchestrator:
kubectl apply -f infra/k8s/configmap.yaml
kubectl rollout restart deployment orchestrator
The keys are stored in the Kubernetes secret app-secrets (set during Phase 12). They are NOT read from GitHub Actions secrets — the pipeline never touches app-secrets.
If you generated new LangFuse keys after Phase 12, you must update the secret manually:
kubectl get secret app-secrets -o jsonpath='{.data.LANGFUSE_PUBLIC_KEY}' | base64 --decode
If the key shown is wrong, update it:
kubectl create secret generic app-secrets --dry-run=client -o yaml ^
--from-literal=LANGFUSE_PUBLIC_KEY=pk-lf-YOUR-KEY ^
--from-literal=LANGFUSE_SECRET_KEY=sk-lf-YOUR-KEY ^
| kubectl apply -f -
kubectl rollout restart deployment orchestrator
After opening a PR, check orchestrator logs for errors:
kubectl logs -l app=orchestrator --tail=50 | grep -i "langfuse\|401\|export"
Failed to export span batch code: 401 means either wrong keys or wrong host region. Fix using 17.2 and 17.3.
Go to your region URL and log in → click your ai-code-reviewer project → Traces in the left sidebar.
After a PR is analyzed you will see:
- One trace per PR
- 4 spans inside each trace running in parallel (static_analysis, security, style, architecture)
- Exact prompt sent and response received per span
- Token count, cost, and latency per call
Now that your system is deployed and you have a public URL, you need to tell GitHub where to send webhook events.
First get your ingress address:
kubectl get ingress gateway-ingress
Your current ingress address is:
k8s-default-gatewayi-d0c66c7699-299311758.us-east-1.elb.amazonaws.com
Your full webhook URL is:
http://k8s-default-gatewayi-d0c66c7699-299311758.us-east-1.elb.amazonaws.com/webhook/github
Now update the GitHub App:
- Go to GitHub → click your profile picture → Settings
- Left sidebar → "Developer settings" → "GitHub Apps"
- Click "Edit" next to
ai-code-reviewer-bot - Find the "Webhook URL" field
- Delete
https://placeholder.com - Enter:
http://k8s-default-gatewayi-d0c66c7699-299311758.us-east-1.elb.amazonaws.com/webhook/github - The "Webhook secret" field should still have the value you set in Step 8.2 — do not change it
- Click "Save changes"
Your system is now fully connected. GitHub will send events to your running service.
The GitHub App must be installed on whichever repository you want the bot to review.
- Go to GitHub → click your profile picture → Settings
- Left sidebar → Developer settings → GitHub Apps
- Click Edit next to
ai-code-reviewer-bot - Left sidebar → click Install App
- Click Install next to your account
- Select Only select repositories
- Choose the repository you want to test with (e.g.
gmail-ai-analyze) - Click Install
Before testing, confirm every service is up:
kubectl get pods
All pods must show Running. If any show Pending or CrashLoopBackOff, wait and run again.
Increment the deploy.txt files to trigger all pipelines:
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer"
echo 2 > services\gateway\deploy.txt && echo 2 > services\webhook\deploy.txt && echo 2 > services\orchestrator\deploy.txt && echo 2 > services\reviewer\deploy.txt && echo 2 > services\learner\deploy.txt
git add services\
git commit -m "deploy: trigger all pipelines for end-to-end test"
git push origin main
Go to GitHub → Actions tab. Wait until all 5 pipelines show green checkmarks on all 3 jobs (test → build-and-push → deploy).
Then run again and confirm all pods are Running:
kubectl get pods
Do everything directly on the GitHub website — no CMD needed.
Step 1 — Go to your test repository on GitHub
(e.g. https://github.com/YOUR_USERNAME/gmail-ai-analyze)
Step 2 — Create a new branch:
- Click the branch dropdown at the top left (shows
main) - Type
test-ai-reviewin the box - Click "Create branch: test-ai-review"
Step 3 — Create a test file:
- Make sure you are on the
test-ai-reviewbranch - Click "Add file" → "Create new file"
- Name the file
test_code.py - Paste this code into the editor:
def calculate(a,b):
password = "admin123"
result = eval(a+b)
return result- Click "Commit changes" → "Commit directly to test-ai-review branch" → "Commit changes"
Step 4 — Open a Pull Request:
- GitHub will show a yellow banner "Compare & pull request" — click it
- Click "Create pull request"
Step 5 — Wait 30-60 seconds
The bot ai-code-reviewer-bot will automatically post review comments on the PR.
Step 6 — Check for comments:
- Click the "Files changed" tab on the PR
- You should see inline comments from
ai-code-reviewer-botpointing out issues like hardcoded password and dangerous use ofeval()
If comments appear — your system is working end-to-end.
How to get the URL:
kubectl get svc -n monitoring grafana
Copy the EXTERNAL-IP and open http://EXTERNAL-IP in your browser.
Login:
- Username:
admin - Password: the one you set in Step 16.7
What to look at:
- Select your imported dashboard from the dashboards list
- Each service has three panels: request rate, p99 latency, error rate
- If error rate spikes, something is broken
- If p99 latency spikes, something is slow
- Dashboard refreshes every 30 seconds automatically
How to open it (runs locally via port-forward):
Open CMD and run:
kubectl port-forward -n monitoring svc/prometheus-server 9090:80
Keep this CMD window open. Then open your browser and go to: http://localhost:9090
Useful queries to try:
- Type
upand click Execute — shows which services are being scraped (value 1 = up, 0 = down) - Type
http_requests_total— shows total request counts per service - Type
rate(http_requests_total[5m])— shows requests per second averaged over 5 minutes
Press Ctrl+C in the CMD window when you want to stop the port-forward.
How to open:
- EU accounts: https://cloud.langfuse.com
- US accounts: https://us.cloud.langfuse.com
Log in and click on the ai-code-reviewer project.
Key sections:
- Traces — one entry per PR analyzed. Shows the full timeline of all 4 agent calls.
- Generations — every individual OpenAI API call with full prompt and response
- Dashboard — total token usage, cost over time, average latency
- Users — which repos triggered the most analyses
How to open: Go to https://github.com/YOUR_USERNAME/ai-code-reviewer and click the "Actions" tab.
What to look at:
- Every row is one deployment triggered by a
git push - Green checkmark = deployed successfully
- Red X = something failed — click to see which step failed and read the error
To see what is happening inside any service right now, open CMD and run:
kubectl logs -l app=gateway -f
Replace gateway with any service name: webhook, orchestrator, reviewer, learner, webhook-worker, learner-worker
The -f flag means "follow" — it streams new log lines as they arrive, like a live tail. Press Ctrl+C to stop.
To see the status of all running containers:
kubectl get pods
To see CPU and memory usage of each pod:
kubectl top pods
To see detailed information about a specific pod (useful for debugging crashes):
kubectl describe pod POD_NAME
Replace POD_NAME with an actual pod name from kubectl get pods.
Every Monday at 9am UTC, GitHub Actions automatically runs scripts/evaluate.py. This evaluates the quality of the AI-generated code review comments.
- Connects to your RDS PostgreSQL database using the DATABASE_URL secret
- Queries the last 50 findings (AI comments) that were generated across all reviewed PRs
- Builds a dataset from those findings
- Runs RAGAS evaluation — a framework for measuring AI answer quality
- Checks two metrics:
- Faithfulness — are the comments grounded in the actual code diff?
- Answer Relevancy — are the comments relevant to the question "what issues exist in this code?"
- Prints the scores
- If faithfulness score is below 0.7 (70%), the job fails and you get a notification email from GitHub
- Go to GitHub → Actions tab
- Look for the "Evaluate" workflow in the left sidebar
- Click on the latest run
- Click on the "evaluate" job
- Expand the "Run evaluation" step
- You will see output like:
Mean faithfulness: 0.84
A score below 0.7 means the AI is generating low-quality or hallucinated comments. To investigate:
- Go to LangFuse → Traces
- Look at the most recent PR analyses
- Read the AI responses in each span
- If the responses are off-topic, the system prompts in
services/orchestrator/graph.pyneed tuning - If the responses are malformed JSON, the parsing in graph.py needs a fix
After the full setup, use these commands to verify your system is healthy.
Check all pods are running:
kubectl get pods
Every pod should show Running and 1/1 under READY.
Check all Kubernetes services exist:
kubectl get svc
Check health endpoint of the gateway:
Open a second CMD window and run:
kubectl port-forward svc/gateway 8000:8000
In your first CMD window run:
curl http://localhost:8000/health
Expected response: {"status":"ok"}
If curl is not available in CMD, open PowerShell and run:
Invoke-WebRequest -Uri http://localhost:8000/health
Check the database tables were created:
kubectl exec -it deployment/webhook -- python -c "import asyncio, sqlalchemy, os; from sqlalchemy.ext.asyncio import create_async_engine; e = create_async_engine(os.environ['DATABASE_URL']); asyncio.run(e.connect()).__enter__(); print('DB OK')"
Check Prometheus is scraping your services:
- Open
http://localhost:9090(after port-forwarding Prometheus from Step 20) - Click "Status" in the top menu → "Targets"
- All 5 service targets (gateway, webhook, orchestrator, reviewer, learner) should show a green "UP" badge
kubectl describe pod POD_NAME
Look at the "Events" section at the bottom. Common causes:
Insufficient cpuorInsufficient memory— your EKS nodes are out of capacity. Go to Terraform and increasedesired_sizeto 3, runterraform apply.ImagePullBackOff— the Docker image does not exist in ECR. Go to GitHub Actions and re-run thebuild-and-pushjob.
kubectl logs POD_NAME --previous
This shows the logs from before it crashed. Common causes:
- Wrong
DATABASE_URLformat — must start withpostgresql+asyncpg:// - Missing environment variable — check that your
secret.yamlhas all the required keys and was applied - Python import error — read the full traceback in the logs
- Go to GitHub → Settings → Developer settings → GitHub Apps → ai-code-reviewer-bot
- Click "Advanced" in the left sidebar
- Under "Recent Deliveries" you can see every webhook event GitHub tried to send
- Click on a failed delivery to see the HTTP response your server returned
- Common causes:
404— the webhook URL path is wrong. It must end with/webhook/github401— the webhook secret in your k8s secret does not match the one set in the GitHub App- Connection refused — the ingress is not created yet. Check
kubectl get ingress
Check orchestrator logs:
kubectl logs -l app=orchestrator -f
Check reviewer logs:
kubectl logs -l app=reviewer -f
Common causes:
- OpenAI API key is invalid — check platform.openai.com/usage to see if calls are being made
- OpenAI account has no credits — add credits at platform.openai.com/billing
- GitHub App does not have Pull requests: Read and Write permission — check Step 8.3
- Private key format is wrong in secrets — the key must preserve line breaks
AWS allows only 5 VPCs per region by default. Either delete an old VPC in the AWS Console (VPC service → Your VPCs → delete one you do not need), or request a limit increase: go to AWS Support → create a case → Service limit increase → VPC.
Your kubeconfig token has expired. Run this again:
aws eks update-kubeconfig --name ai-code-reviewer --region us-east-1
Fixed monthly AWS costs (running 24/7):
| Resource | Specification | Monthly Cost |
|---|---|---|
| EKS Cluster control plane | managed | $72 |
| EKS Worker Nodes | 2x t3.medium | $60 |
| RDS PostgreSQL | db.t3.micro, 20 GB | $15 |
| ElastiCache Redis | cache.t3.micro | $12 |
| Application Load Balancer | for ingress + Grafana | $18 |
| ECR storage | 5 repos, ~500 MB each | $1 |
| S3 bucket | minimal storage | $1 |
| Total AWS per month | ~$179 |
Usage-based costs:
| Resource | Cost |
|---|---|
| OpenAI GPT-4o-mini | ~$0.15 per 100 PRs reviewed |
| LangFuse | Free up to 50,000 events/month |
To pause the system and stop all charges:
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\terraform"
terraform destroy -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!"
Type yes when asked. This deletes everything on AWS. You can recreate it later with terraform apply.
To just scale down (reduce cost, keep data):
Scale EKS nodes to 1:
- Open
infra\terraform\main.tf - Change
desired_size = 2todesired_size = 1 - Run
terraform applyagain
Open Grafana:
Run: kubectl get svc -n monitoring grafana
Open: http://EXTERNAL-IP in browser
Login: admin / your-password
Open Prometheus:
Run: kubectl port-forward -n monitoring svc/prometheus-server 9090:80
Open: http://localhost:9090 in browser
(keep CMD window open while using it)
Open LangFuse:
EU: https://cloud.langfuse.com
US: https://us.cloud.langfuse.com
Check all pods:
kubectl get pods
Watch live logs:
kubectl logs -l app=gateway -f
kubectl logs -l app=orchestrator -f
kubectl logs -l app=reviewer -f
Deploy new code:
git add .
git commit -m "your message"
git push origin main
Scale a service:
kubectl scale deployment orchestrator --replicas=4
Shut down everything (stop AWS charges):
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\terraform"
terraform destroy -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!" -var="environment=production"
Run this when you want to shut everything down and stop all AWS charges.
cd "D:\MAJOR PROJECT KRISH SIR\ai-code-reviewer\infra\terraform"
terraform destroy -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!" -var="environment=production"
Terraform will show everything it plans to delete and ask:
Do you really want to destroy all resources? Enter a value:
Type yes and press Enter. This takes 10-15 minutes.
Terraform sometimes misses resources that were created outside of it (like load balancers created by Kubernetes). Check and delete these manually:
Load Balancers:
aws elbv2 describe-load-balancers --query "LoadBalancers[].LoadBalancerArn" --output text
If anything is listed, delete each one:
aws elbv2 delete-load-balancer --load-balancer-arn YOUR_ARN
EBS Volumes (created by Prometheus/Grafana PVCs):
aws ec2 describe-volumes --filters "Name=status,Values=available" --query "Volumes[].VolumeId" --output text
If anything is listed, delete each one:
aws ec2 delete-volume --volume-id YOUR_VOLUME_ID
CloudWatch Log Groups:
aws logs describe-log-groups --log-group-name-prefix "/aws/eks" --query "logGroups[].logGroupName" --output text
Delete each one:
aws logs delete-log-group --log-group-name YOUR_LOG_GROUP
aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId" --output text
aws elbv2 describe-load-balancers --query "LoadBalancers[].LoadBalancerArn" --output text
Both should return empty. You are now fully cleaned up with zero ongoing charges.
Just follow the documentation from Phase 8 onwards — run terraform apply, apply the k8s manifests, trigger the pipelines. Everything will come back up exactly as before.
Terraform only destroys what it created. The AWS Load Balancer Controller creates load balancers and security groups dynamically at runtime — Terraform has no record of these and will fail with DependencyViolation if they still exist when destroying the VPC.
Always follow this exact order:
kubectl delete ingress --all
kubectl delete svc --allWait 1-2 minutes for AWS to release the load balancers automatically.
Check what security groups remain:
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=YOUR_VPC_ID" --query "SecurityGroups[*].[GroupId,GroupName]" --output tableDelete any security group whose name starts with k8s-:
aws ec2 delete-security-group --group-id YOUR_SG_IDDo not delete the default security group — Terraform handles that.
aws elbv2 describe-load-balancers --query "LoadBalancers[*].LoadBalancerArn" --output textDelete each one:
aws elbv2 delete-load-balancer --load-balancer-arn YOUR_ARNcd infra\terraform
terraform destroy -var="cluster_name=ai-code-reviewer" -var="db_password=YourStrongPassword123!"Type yes when prompted. This will now complete cleanly.
All ECR repositories have force_delete = true in Terraform — so even if they contain Docker images, Terraform will delete them without errors.