Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/yohangr3/agentelanggrafh/llms.txt

Use this file to discover all available pages before exploring further.

The ERP Financial Agent runs on AWS ECS Fargate behind an Application Load Balancer. Three CloudFormation stacks describe the full infrastructure: the network layer (VPC, subnets, NAT), the services layer (ECS cluster, task definitions, ALB, ECR, ElastiCache, DynamoDB), and the CI/CD layer (GitHub OIDC provider and the IAM role that GitHub Actions assumes). A deploy.sh script ties them together for an initial rollout; subsequent deployments are fully automated via GitHub Actions.

Architecture overview

Internet


Application Load Balancer  (public subnets: 10.0.1.0/24, 10.0.2.0/24)


ECS Fargate Tasks          (private subnets: 10.0.10.0/24, 10.0.20.0/24)
├── frontend container (nginx :80)
└── backend container  (uvicorn :8000)

          ├── ElastiCache Redis (cache.t3.micro, port 6379)
          ├── RDS MySQL         (via Secrets Manager password)
          ├── AWS Bedrock       (Anthropic Claude models)
          └── DynamoDB          (conversation history, query log)

   NAT Gateway               (outbound internet for ECR pulls, Bedrock)
The ALB sits in two public subnets across two availability zones for high availability. ECS tasks run in private subnets and reach the internet only through a single NAT Gateway (placed in PublicSubnet1 for cost optimization). Redis and RDS are similarly restricted to the private subnets.

CloudFormation stacks

Creates the entire network layer. Resources are tagged with Project: erp-agent and the environment name.
ResourceValue
VPC CIDR10.0.0.0/16
Public subnet 110.0.1.0/24 (AZ-a) — ALB + NAT Gateway
Public subnet 210.0.2.0/24 (AZ-b) — ALB high availability
Private subnet 110.0.10.0/24 (AZ-a) — ECS + ElastiCache
Private subnet 210.0.20.0/24 (AZ-b) — ECS + ElastiCache HA
NAT GatewayElastic IP in PublicSubnet1
ALB security groupAllows TCP 80 from 0.0.0.0/0
ECS security groupAllows TCP 80 from ALB security group only
Redis security groupAllows TCP 6379 from ECS security group only
Stack outputs ({EnvironmentName}-*) are imported by the services stack: VpcId, PublicSubnet1Id, PublicSubnet2Id, PrivateSubnet1Id, PrivateSubnet2Id, ALBSecurityGroupId, ECSSecurityGroupId, RedisSecurityGroupId.
Creates all compute and data resources. It imports networking outputs from the network stack.ECS task definition (erp-agent-task-{env}):
  • CPU: 2048 (2 vCPU)
  • Memory: 4096 MB
  • Two containers: backend (port 8000) and frontend (port 80)
  • Network mode: awsvpc — each task gets its own ENI in a private subnet
Task IAM roles:
  • Execution role — pulls images from ECR, writes to CloudWatch Logs, reads the DB password from Secrets Manager
  • Task role — calls bedrock:InvokeModel / bedrock:ConverseStream on Anthropic and Amazon Titan models; reads/writes erp-agent-conversations, erp-agent-query-log, and erp-agent-rbac-overrides DynamoDB tables; puts/gets objects in the exports S3 bucket
Auto-scaling: target tracking on ECSServiceAverageCPUUtilization at 70% CPU (configurable via CpuTarget). Scale-out cooldown is 60 s; scale-in cooldown is 300 s. Maximum capacity is 4 tasks.ALB target group health check: GET /health on port 80, HTTP 200, every 30 seconds. Stickiness is enabled with a 1-hour lb_cookie.CloudWatch alarms: high CPU (>80% for 3 minutes), unhealthy hosts (>0 for 2 minutes), HTTP 5xx errors (>10 per minute for 2 minutes).DynamoDB tables (on-demand billing, created only on the primary stack):
  • erp-agent-conversations — partition key user_id, sort key session_id, TTL on ttl
  • erp-agent-query-log — partition key query_id, sort key timestamp
Provisions the trust relationship between GitHub Actions and AWS using OIDC — no long-lived access keys needed.
  • Creates (or imports) an AWS::IAM::OIDCProvider for token.actions.githubusercontent.com
  • Creates the github-actions-erp-agent IAM role, trusted only by the configured GitHubOrg/GitHubRepo
  • Grants the role: ECR push, ECS UpdateService + RegisterTaskDefinition, CloudWatch Logs, Bedrock invocation (for evaluation workflows), Secrets Manager read, and full provisioning permissions for tenant stacks
After deploying this stack, copy the GitHubActionsRoleArn output and store it as the AWS_ROLE_ARN secret in your GitHub repository settings.

Initial deployment

1

Install and configure the AWS CLI

aws configure
# Region: us-east-1
# Output: json
2

Deploy the network stack

cd infra/cloudformation
./deploy.sh network
This creates the erp-agent-network stack. Wait for the stack to reach CREATE_COMPLETE before proceeding — the services stack imports its outputs.
3

Deploy the services stack

DB_PASSWORD="your-database-password" ./deploy.sh services
The script prompts for DB_PASSWORD if the environment variable is not set. The password is stored in Secrets Manager as erp-agent/db-password and injected into the ECS task at runtime — it never appears in plaintext in the task definition.This step creates the ECR repositories (erp-agent/backend and erp-agent/frontend) that you will push images to in the next step.
4

Build and push Docker images to ECR

# Authenticate to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS \
  --password-stdin <account-id>.dkr.ecr.us-east-1.amazonaws.com

# Build and push backend
docker build -t erp-agent/backend -f infra/docker/Dockerfile .
docker tag erp-agent/backend \
  <account-id>.dkr.ecr.us-east-1.amazonaws.com/erp-agent/backend:latest
docker push \
  <account-id>.dkr.ecr.us-east-1.amazonaws.com/erp-agent/backend:latest

# Build and push frontend
docker build -t erp-agent/frontend ./frontend
docker tag erp-agent/frontend \
  <account-id>.dkr.ecr.us-east-1.amazonaws.com/erp-agent/frontend:latest
docker push \
  <account-id>.dkr.ecr.us-east-1.amazonaws.com/erp-agent/frontend:latest
5

Deploy the CI/CD stack

./deploy.sh cicd
Copy the GitHubActionsRoleArn output:
aws cloudformation describe-stacks \
  --stack-name erp-agent-cicd \
  --query "Stacks[0].Outputs[?OutputKey=='GitHubActionsRoleArn'].OutputValue" \
  --output text
Add this ARN as the AWS_ROLE_ARN secret in your GitHub repository.
To deploy all three stacks in sequence, run ./deploy.sh (or ./deploy.sh all) with no arguments. Validation runs before any stack is created.

GitHub Actions CI/CD

The .github/workflows/deploy.yml pipeline has three stages that run in order.
push to dev   →  CI Pipeline  →  deploy-staging
push to main  →  CI Pipeline  →  deploy-production  →  refresh-tenants
Triggered automatically when the CI pipeline succeeds on the dev branch, or via workflow_dispatch with environment: staging.
  1. Assumes AWS_ROLE_ARN via OIDC (id-token: write permission)
  2. Logs in to ECR
  3. Fetches the current task definition JSON with aws ecs describe-task-definition
  4. Patches both container images using jq and registers a new task definition revision
  5. Calls aws ecs update-service --force-new-deployment
  6. Waits for services-stable (5-minute timeout)

ECS task environment variables

The task definition injects the following environment variables into the backend container. Secrets are fetched from Secrets Manager at task startup and are never written to CloudWatch Logs.
VariableSourceExample value
DB_HOSTCloudFormation parameteriafinagent.choi0eaq2mr7.us-east-1.rds.amazonaws.com
DB_NAMECloudFormation parameteriafinagent
DB_USERCloudFormation parameteradmin
DB_PASSWORDSecrets Managererp-agent/db-password
REDIS_URLElastiCache endpointredis://<endpoint>:6379/0
AWS_REGIONAWS::Regionus-east-1
COGNITO_USER_POOL_IDCloudFormation parameterus-east-1_2qpNBGCmb
COGNITO_CLIENT_IDCloudFormation parameter70qcoifagu4tk20qnn2q8d9rjs
BEDROCK_MODEL_IDHardcoded in templateus.anthropic.claude-sonnet-4-5-20250929-v1:0
BEDROCK_REASONING_MODEL_IDHardcoded in templateus.anthropic.claude-sonnet-5
BEDROCK_EMBEDDING_MODEL_IDHardcoded in templateamazon.titan-embed-text-v2:0
DYNAMODB_ENABLEDHardcodedtrue
EXPORTS_BUCKET_NAMES3 bucket from ExportsBucket outputerp-agent-exports-<account-id>
ENVIRONMENTCloudFormation parameterproduction
EXPECTED_TENANTCloudFormation parameter* (primary) or tenant slug
RBAC_ENFORCECloudFormation parameterfalse
LOG_LEVELHardcodedINFO

Validate templates without deploying

./deploy.sh validate
Runs aws cloudformation validate-template against all three templates and exits non-zero if any are invalid.

Build docs developers (and LLMs) love