AWS Architecture
Carbon Connect runs on AWS in the eu-north-1 (Stockholm) region using a hybrid serverless architecture with ECS Fargate for compute and managed services for data.
Architecture Diagram
flowchart TB
subgraph Internet
U[Users / Browsers]
GH[GitHub Actions<br/>CI/CD via OIDC]
end
subgraph AWS["AWS eu-north-1"]
subgraph Public["Public Subnets"]
ALB[Application Load Balancer<br/>+ WAF]
NAT[NAT Gateway]
end
subgraph Private["Private Subnets"]
subgraph ECS["ECS Fargate Cluster"]
API[API Service<br/>FastAPI]
Worker[Celery Worker<br/>Fargate Spot]
Beat[Celery Beat<br/>Scheduler]
end
MS[Meilisearch<br/>Search Engine]
end
subgraph Data["Data Subnets"]
RDS[(RDS PostgreSQL 16<br/>+ pgvector)]
EC[(ElastiCache<br/>Valkey Serverless)]
end
subgraph Storage["S3 Buckets"]
S3D[Documents Bucket]
S3M[Media Bucket]
end
subgraph Security["Security"]
SM[Secrets Manager<br/>API Keys, DB Pass]
IAM[IAM Roles<br/>OIDC Provider]
KMS[KMS<br/>Encryption Keys]
end
subgraph Monitoring
CW[CloudWatch<br/>Logs + Metrics]
CI[Container Insights]
end
end
U -->|HTTPS| ALB
GH -->|OIDC| IAM
ALB -->|Port 8000| API
API --> RDS
API --> EC
API --> MS
Worker --> RDS
Worker --> EC
Beat --> EC
API --> S3D
API --> S3M
API --> SM
ECS --> CW
ECS --> CI
Private -->|Outbound| NAT
NAT -->|Internet| Internet
VPC Layout
The VPC uses a three-tier subnet architecture across three availability zones:
| Subnet Tier | CIDR Range | Purpose | Internet Access |
| Public | 10.0.0.0/20 - 10.0.32.0/20 | ALB, NAT Gateway | Direct (IGW) |
| Private | 10.0.48.0/20 - 10.0.80.0/20 | ECS tasks, Meilisearch | Outbound only (NAT) |
| Data | 10.0.96.0/20 - 10.0.128.0/20 | RDS, ElastiCache | No internet access |
VPC CIDR: 10.0.0.0/16 (65,536 addresses)
Availability Zones
eu-north-1a eu-north-1b eu-north-1c
NAT Gateway Strategy
- Development/Staging: Single NAT Gateway (cost savings)
- Production: NAT Gateway per AZ (high availability)
Service Details
RDS PostgreSQL
| Setting | Default | Description |
| Instance class | db.t4g.medium | Graviton ARM (20% savings over Intel) |
| Engine version | PostgreSQL 16 | With pgvector extension |
| Storage | 50 GB (auto-scale to 200 GB) | General Purpose SSD (gp3) |
| Multi-AZ | false (dev), true (prod) | Standby replica for failover |
| Backup retention | 7 days | Automated daily backups |
| Deletion protection | false (dev), true (prod) | Prevents accidental deletion |
| Extensions | vector, uuid-ossp | pgvector for embedding search |
ElastiCache (Valkey)
| Setting | Default | Description |
| Engine | Valkey | 20% cheaper than Redis |
| Mode | Serverless (dev/staging) | Auto-scaling, pay-per-use |
| Node type | cache.t4g.medium (prod) | Graviton ARM |
| Nodes | 1 (dev), 2+ (prod) | Read replicas for production |
ECS Fargate
API Service:
| Setting | Default | Description |
| CPU | 1024 (1 vCPU) | Fargate compute units |
| Memory | 2048 MB (2 GB) | Container memory |
| Desired count | 2 | Running tasks |
| Auto-scale | 1-10 | Based on CPU/memory utilization |
| Capacity provider | Fargate (on-demand) | Guaranteed availability |
Worker Service:
| Setting | Default | Description |
| CPU | 1024 (1 vCPU) | Fargate compute units |
| Memory | 2048 MB (2 GB) | Container memory |
| Desired count | 2 | Running tasks |
| Auto-scale | 1-10 | Based on queue depth |
| Capacity provider | Fargate Spot | 70% cost savings |
Application Load Balancer
| Feature | Configuration |
| Type | Application (Layer 7) |
| Listeners | HTTP (80) -> HTTPS redirect, HTTPS (443) |
| Target group | API containers on port 8000 |
| Health check | GET /api/v1/health |
| WAF | AWS WAF with rate limiting |
| WAF rate limit | 2000 requests per 5 minutes per IP |
S3 Buckets
| Bucket | Purpose | Lifecycle |
{project}-{env}-documents | Application documents, reports | Standard -> Intelligent-Tiering -> Glacier |
{project}-{env}-media | Company logos, images | Standard (no lifecycle) |
Both buckets have public access blocked and server-side encryption (AES-256).
Secrets Manager
The secrets module stores sensitive configuration:
| Secret | Description |
| Database password | Auto-generated RDS master password |
| Application secrets | JWT secret, session key |
| Claude API key | Anthropic API key |
| Climatiq API key | Carbon calculation API key |
| Meilisearch key | Search engine master key |
Security
Network Security
- Public subnets: Only ALB and NAT Gateway
- Private subnets: ECS tasks with outbound-only internet access
- Data subnets: No internet access, only accessible from private subnets
- Security groups enforce least-privilege network access
IAM
- ECS task execution role: Pull images from ECR, read secrets
- ECS task role: Access S3, Secrets Manager, CloudWatch
- GitHub Actions: OIDC-based federation (no long-lived credentials)
Encryption
- RDS: Encrypted at rest (AES-256 via KMS)
- ElastiCache: Encryption in transit and at rest
- S3: Server-side encryption (AES-256)
- ALB: TLS 1.2+ for all HTTPS traffic
Cost Optimization
| Strategy | Service | Savings |
| Graviton (ARM64) | RDS, ElastiCache | ~20% |
| Fargate Spot | Celery workers | ~70% |
| Valkey Serverless | Cache (dev/staging) | Pay-per-use |
| S3 Intelligent-Tiering | Documents | Automatic tier optimization |
| Single NAT Gateway | Non-production | ~66% NAT cost |