A simple To-Do application built for testing Infrastructure as Code (IaC) translation between AWS, Azure, and GCP.
This base app will be used for our discovery cycle to test how AI tools translate Infrastructure as Code (IaC) between AWS, Azure, and GCP—using a simple full-stack app—to simplify migrations. The goal is to assess tool effectiveness, with deliverables including findings, guidance, and a practical playbook for engineers and architects.
This base app is AWS-native and designed to be translated to other cloud platforms using AI tools.
- Frontend: React SPA with modern, sleek UI
- Backend: Node.js/Express API
- Database: RDS PostgreSQL (AWS) / Local JSON for development
- Infrastructure: AWS ECS Fargate, RDS, Secrets Manager, VPC (simplified for discovery cycle)
- Secrets Management: AWS Secrets Manager (production) / Environment variables (local)
- Node.js 18+
- Docker & Docker Compose
- AWS CLI (for cloud deployment)
- Terraform (for infrastructure)
-
Clone and setup:
git clone <repo-url> cd IaC_TRANSIT_baseapp cp .env.example .env.local
-
Set up sensitive environment variables (required):
Export database credentials via terminal before running docker compose (use any username/password you prefer):
export DB_USER=todoapp_user export DB_PASSWORD=todoapp_password docker compose up
Note: Sensitive credentials must be set via terminal exports, not stored in files. This prevents accidental exposure to AI tools like Cursor.
-
Start the application:
# Using Docker Compose (recommended) docker compose up # Or manually cd backend && npm install && npm start cd frontend && npm install && npm start
-
Access the app: http://localhost:3000
If multiple participants are deploying to the same AWS account, you must customize resource names to avoid conflicts:
terraform apply \
-var="project_name=YOUR_UNIQUE_NAME" \
-var="environment=YOUR_ENV" \
-var="aws_region=us-east-1" \
-var="db_password=YourSecurePassword123"Example: If you're Alice and Bob is also deploying:
- Alice uses:
-var="project_name=alice-todoapp" -var="environment=prod" - Bob uses:
-var="project_name=bob-todoapp" -var="environment=staging"
This creates unique resource names (alice-todoapp-prod-* vs bob-todoapp-staging-*) and prevents naming conflicts.
If each participant has their own AWS account, the default values are fine.
-
Create AWS Secrets Manager secret:
aws secretsmanager create-secret \ --name todoapp-secrets \ --description "Todo app database credentials" \ --secret-string '{ "db_host": "your-rds-endpoint.amazonaws.com", "db_port": "5432", "db_name": "todoapp", "db_user": "todoapp_user", "db_password": "your_secure_password" }'
-
Deploy infrastructure:
cd infrastructure terraform init terraform plan terraform apply -
Deploy application:
./scripts/deploy.sh
To destroy all AWS resources and stop incurring costs:
./scripts/destroy.shThis will:
- Destroy all Terraform-managed resources
- Delete ECS services, tasks, and clusters
- Delete RDS instances
- Remove VPC, subnets, and security groups
- Keep CloudWatch logs for 30 days (retention policy)
- Create RDS final snapshot before deletion
API_PORT=3001
NODE_ENV=development
AWS_REGION=us-east-1
SECRETS_MANAGER_SECRET_NAME=todoapp-secrets
REACT_APP_API_URL=http://localhost:3001DB_HOST=localhost
DB_PORT=5432
DB_NAME=todoapp
DB_USER=todoapp_user
DB_PASSWORD=your_passwordThis project uses a two-tier approach for environment management:
- What goes here: Database host, port, name, API port, frontend URLs, Node environment
- Storage:
.env.local(gitignored, safe to commit to.gitignore) - Use case: Shared configuration that developers need to customize locally
- Example: See
.env.example(committed to git)
- What goes here: Database username, password, API keys, secrets
- Storage: Terminal environment variables ONLY (
export DB_USER=...) - Never: Store in
.env,.env.local, or any file - Use case: Prevents accidental exposure to version control and AI tools
Setup:
# Copy non-sensitive config
cp .env.example .env.local
# Export sensitive credentials in current shell
export DB_USER=todoapp_user
export DB_PASSWORD=todoapp_password
# Then run docker compose
docker compose up- Excludes files from Cursor AI context and indexing
- NOT a complete security guarantee - it's a convenience feature
- Files listed may still be accessed through system commands or indirect methods
Do NOT rely on .cursorignore to protect sensitive data. Even with .cursorignore, credentials in files can potentially be exposed through:
- File system access
- System command execution
- Indirect references
- Caching
The safe approach: Keep sensitive data in terminal environment variables only, never in files.
We use .cursorignore to exclude:
.env.localand.env.*- Key files, certificates, secrets directories
- Node modules, build artifacts, etc.
This helps reduce noise in AI processing, but primary protection comes from not storing secrets in files.
For production deployment:
- Store all secrets in AWS Secrets Manager
- Retrieve at runtime via AWS SDK
- Never commit or expose credentials
- See AWS Deployment section for setup
✅ DO:
- Keep sensitive credentials in terminal exports or AWS Secrets Manager
- Use
.env.localfor non-sensitive configuration only - Add sensitive file patterns to
.cursorignoreand.gitignore - Rotate credentials regularly
- Use strong, unique passwords
❌ DON'T:
- Store secrets in
.env,.env.local, or any committed file - Rely solely on
.cursorignorefor security - Share terminal exports or commit env files
- Use default/simple passwords in production
- Log sensitive information
This AWS-native application is designed to be translated to other cloud platforms:
- ECS → Azure Container Instances
- RDS → Azure Database for PostgreSQL
- Secrets Manager → Azure Key Vault
- VPC → Azure Virtual Network
- CloudWatch Logs → Azure Monitor / Azure Log Analytics
- ECS → Cloud Run
- RDS → Cloud SQL
- Secrets Manager → Secret Manager
- VPC → VPC Network
- CloudWatch Logs → Cloud Logging
The application includes comprehensive logging in both local and cloud environments:
- Log files:
backend/logs/*.log(info.log, error.log, warn.log, debug.log) - Features: Timestamps, log levels, structured metadata
- Cost: Free (local file storage)
- Service: CloudWatch Logs
- Log group:
/ecs/todoapp-dev - Retention: 30 days
- Cost: ~$2–5/month
- Access: AWS Console → CloudWatch → Log Groups
- API request logging (endpoint, method, IP, user agent)
- Database operations (connections, queries)
- Error tracking (stack traces, context)
- Application events (startup, shutdown, health checks)
- Real-time log streaming
For detailed logging documentation, see docs/api.md.
GET /api/todos- Get all todosPOST /api/todos- Create a new todoPUT /api/todos/:id- Update a todoDELETE /api/todos/:id- Delete a todoGET /api/health- Health check
This is a base template for IaC translation testing. Feel free to modify and extend as needed for your specific use case.
- RDS: ~$15–20/month (db.t3.micro, 31-day backups)
- ECS Fargate: ~$10–15/month (256 CPU, 512 MB)
- VPC Flow Logs: ~$0.50/month (CloudWatch Logs ingestion)
- KMS encryption: ~$1/month (CMK for logs)
- Data transfer: minimal for testing
Total: ~$27–37/month for the simplified stack.
Note: ALB and NAT Gateways have been removed to reduce costs for the discovery cycle. ECS tasks run in public subnets with direct public IPs, while RDS remains in private subnets for security.
AWS Compliance Updates: The infrastructure now includes VPC Flow Logs, KMS-encrypted CloudWatch Logs, extended RDS backup retention (31 days), and restrictive security group rules to meet AWS baseline compliance requirements.
This application and its Infrastructure as Code were built with the assistance of Cursor, an AI-powered code editor.
MIT
