> ## Documentation Index
> Fetch the complete documentation index at: https://alliancebioversityciat-alliance-risk-analysis-tool.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# AWS Infrastructure Overview

> Complete AWS architecture and resource configuration for the CGIAR Risk Intelligence Tool

The CGIAR Risk Intelligence Tool runs entirely on AWS infrastructure, using a serverless architecture with managed services for scalability, security, and cost optimization.

## Architecture Diagram

```
CloudFront (CDN)
    |
    ├─> S3 (Static Web Hosting)          Next.js SPA
    |
API Gateway (HTTP API)
    |
    └─> API Lambda (NestJS)
            ├─> Cognito User Pool          Authentication
            ├─> RDS PostgreSQL (VPC)       Primary database
            ├─> S3 (File Bucket)           Business plan uploads
            ├─> Bedrock (Claude 3.5)       AI agents (9 agents, 7 KBs)
            ├─> Textract                   Document parsing
            └─> Worker Lambda              Async job processing
```

## Core AWS Resources

### Cognito User Pool

**Purpose:** User authentication and authorization

* **Authentication:** Email-based login with AWS Cognito User Pool
* **Password Policy:**
  * Minimum 12 characters
  * Requires uppercase, lowercase, numbers, and symbols
  * Temporary password valid for 7 days
* **User Groups:** `admin` group for platform administrators
* **Token Validity:**
  * Access token: 60 minutes
  * ID token: 60 minutes
  * Refresh token: 30 days (43,200 minutes)
* **Auth Flows:** `USER_PASSWORD_AUTH`, `ADMIN_USER_PASSWORD_AUTH`, `USER_SRP_AUTH`, `REFRESH_TOKEN_AUTH`
* **Self-signup:** Disabled (admin-only user creation)

**Stack Resource:** `UserPool`, `UserPoolClient`, `AdminGroup`

### RDS PostgreSQL 15

**Purpose:** Primary relational database for all application data

* **Instance Type:** `db.t3.micro` (2 vCPUs, 1 GiB RAM)
* **Storage:** 20 GB General Purpose SSD (gp3)
* **Engine:** PostgreSQL 15
* **Database Name:** `alliance_risk`
* **High Availability:** Single-AZ (MVP configuration)
* **Backup Retention:** 7 days
* **Encryption:** Storage encrypted at rest
* **Network:** Private VPC, no public access
* **Deletion Protection:** Enabled (production)
* **Deletion Policy:** Snapshot (production)

**Credentials:** Stored in AWS Secrets Manager at `alliance-risk/db-credentials`

**Schema Management:** Prisma ORM with migrations in `packages/api/prisma/migrations/`

**Stack Resource:** `Database`, `DbSecret`, `DbSecurityGroup`, `DbSubnetGroup`

### Lambda Functions

Both Lambda functions run on **ARM64 architecture** for cost optimization (20% cheaper than x86\_64).

#### API Lambda

**Purpose:** REST API server (NestJS)

* **Function Name:** `alliance-risk-api`
* **Runtime:** Node.js 20.x (ARM64)
* **Handler:** `dist/src/lambda.handler`
* **Memory:** 1024 MB
* **Timeout:** 29 seconds (\< API Gateway 30s limit)
* **VPC:** Attached to private subnets for RDS access
* **Trigger:** API Gateway HTTP API
* **Environment Variables:**
  * `ENVIRONMENT` — Deployment environment (dev/staging/production)
  * `COGNITO_USER_POOL_ID` — Cognito User Pool ID
  * `COGNITO_CLIENT_ID` — Cognito App Client ID
  * `S3_BUCKET_NAME` — File storage bucket name
  * `AWS_ACCOUNT_ID` — AWS Account ID
  * `WORKER_FUNCTION_NAME` — Worker Lambda function name
  * `CORS_ORIGIN` — Allowed CORS origin
  * `DATABASE_URL` — PostgreSQL connection string (constructed from Secrets Manager)

**Stack Resource:** `ApiLambda`, `ApiLambdaRole`

#### Worker Lambda

**Purpose:** Background job processor for long-running AI operations

* **Function Name:** `alliance-risk-worker`
* **Runtime:** Node.js 20.x (ARM64)
* **Handler:** `dist/src/worker.handler`
* **Memory:** 1024 MB
* **Timeout:** 900 seconds (15 minutes)
* **VPC:** Attached to private subnets for RDS access
* **Invocation:** Asynchronous (fire-and-forget from API Lambda)
* **Environment Variables:**
  * `ENVIRONMENT` — Deployment environment
  * `AWS_ACCOUNT_ID` — AWS Account ID
  * `S3_BUCKET_NAME` — File storage bucket name
  * `DATABASE_URL` — PostgreSQL connection string

**Stack Resource:** `WorkerLambda`, `WorkerLambdaRole`

**Special Action:** `run-sql` — Executes raw SQL on RDS for database migrations (RDS is in private VPC, unreachable from local machines)

### S3 Buckets

#### File Storage Bucket

**Purpose:** Business plan document uploads (PDF/DOCX)

* **Bucket Name:** `alliance-risk-files-{AWS::AccountId}`
* **Public Access:** Blocked (all)
* **Encryption:** S3-managed (AES256)
* **Versioning:** Disabled
* **Deletion Policy:** Retain (production)
* **CORS:** Enabled for presigned upload URLs
  * Allowed origins: `*`
  * Allowed methods: GET, PUT
  * Exposed headers: ETag

**Stack Resource:** `FileBucket`

#### Web Hosting Bucket

**Purpose:** Next.js static site hosting

* **Bucket Name:** `alliance-risk-web-{AWS::AccountId}`
* **Public Access:** Blocked (CloudFront OAI used)
* **Encryption:** S3-managed (AES256)
* **Versioning:** Disabled
* **Deletion Policy:** Delete (auto-cleanup on stack deletion)

**Stack Resource:** `WebBucket`, `WebBucketPolicy`

### CloudFront Distribution

**Purpose:** Global CDN for static web application

* **Origin:** S3 Web Bucket via Origin Access Identity (OAI)
* **Protocol:** HTTPS only (redirect HTTP → HTTPS)
* **Price Class:** 100 (North America + Europe)
* **HTTP Version:** HTTP/2
* **Default Root Object:** `index.html`
* **Error Responses:** 403/404 → 200 with `/index.html` (SPA routing)
* **Cache Policy:** CachingOptimized (`658327ea-f89d-4fab-a63d-7e88639e58f6`)
* **Compression:** Gzip enabled

**URL Rewrite Function:** CloudFront Function that rewrites extensionless URLs to `.html` files for Next.js static export:

* `/login` → `/login.html`
* `/dashboard/` → `/dashboard.html`
* Blocks direct browser navigation to `.txt` files (RSC payloads)

**Stack Resource:** `WebDistribution`, `WebOAI`, `UrlRewriteFunction`

### API Gateway HTTP API

**Purpose:** HTTP API endpoint for REST API

* **Name:** `alliance-risk-api`
* **Protocol:** HTTP (not REST — simpler, cheaper)
* **Integration:** Lambda Proxy (payload format 2.0)
* **CORS:**
  * Allowed origins: `*`
  * Allowed methods: GET, POST, PUT, DELETE, OPTIONS, PATCH
  * Allowed headers: `*`
  * Max age: 86400 seconds (24 hours)
* **Authorization:** None (handled by NestJS JWT guards)
* **Default Route:** All requests route to API Lambda

**Stack Resource:** `HttpApi`, `HttpApiIntegration`, `HttpApiDefaultRoute`, `HttpApiStage`

### IAM Roles and Policies

#### API Lambda Role

Permissions:

* **CloudWatch Logs:** Basic Lambda execution (log creation)
* **VPC Access:** ENI creation for VPC attachment
* **Cognito:** All admin user/group operations
* **Bedrock:** Model invocation and knowledge base retrieval
  * `anthropic.claude-3-5-sonnet-*`
  * `anthropic.claude-3-haiku-*`
* **Textract:** Document analysis
* **S3:** GetObject, PutObject, DeleteObject on FileBucket
* **Lambda:** InvokeFunction on Worker Lambda

**Stack Resource:** `ApiLambdaRole`

#### Worker Lambda Role

Permissions (identical to API Lambda except no Worker invocation):

* **CloudWatch Logs:** Basic Lambda execution
* **VPC Access:** ENI creation for VPC attachment
* **Cognito:** All admin user/group operations
* **Bedrock:** Model invocation and knowledge base retrieval
* **Textract:** Document analysis
* **S3:** GetObject, PutObject, DeleteObject on FileBucket

**Stack Resource:** `WorkerLambdaRole`

## VPC Networking

The RDS database resides in a **private VPC** with no public internet access. Both Lambda functions are deployed inside the same VPC to communicate with the database.

### VPC Configuration

* **VPC:** Default VPC (specified via `VpcId` parameter)
* **Subnets:** Public subnets (specified via `SubnetIds` parameter)
* **Security Groups:**
  * `LambdaSecurityGroup` — Allows all outbound traffic
  * `DbSecurityGroup` — Allows inbound PostgreSQL (5432) from LambdaSecurityGroup only
  * `VpcEndpointSecurityGroup` — Allows HTTPS (443) from LambdaSecurityGroup

### VPC Endpoints

Lambdas in a VPC cannot reach public AWS services (Cognito, Bedrock, S3) without **VPC Endpoints** or a NAT Gateway. The stack provisions the following VPC endpoints:

| Service | Type | Purpose |
| - | - | - |
| **Cognito IDP** | Interface | Token verification, user management |
| **Lambda** | Interface | Worker Lambda invocation from API Lambda |
| **Textract** | Interface | Document parsing |
| **S3** | Gateway | File storage access (cheaper than interface endpoint) |

**Important:** Interface endpoints only support specific Availability Zones. The `EndpointSubnetIds` parameter must specify subnets in supported AZs (e.g., us-east-1a/b/c for Cognito).

**Missing Endpoint:** Bedrock does not have a VPC endpoint yet. The current implementation uses a **NAT Gateway** (not in this template) or direct internet access. This will be addressed in a future update.

### Security Group Rules

```yaml theme={null}
LambdaSecurityGroup:
  Egress: 0.0.0.0/0 (all traffic)

DbSecurityGroup:
  Ingress: LambdaSecurityGroup → 5432/tcp

VpcEndpointSecurityGroup:
  Ingress: LambdaSecurityGroup → 443/tcp
```

## Stack Outputs

The CloudFormation stack exports these outputs for deployment scripts:

| Output Key | Description | Used By |
| - | - | - |
| `ApiUrl` | API Gateway endpoint URL | Web build (`NEXT_PUBLIC_API_URL`) |
| `CloudFrontUrl` | CloudFront distribution URL | Web deployment verification |
| `CloudFrontDistributionId` | CloudFront distribution ID | Web deployment (cache invalidation) |
| `CognitoUserPoolId` | Cognito User Pool ID | Web build (`NEXT_PUBLIC_COGNITO_USER_POOL_ID`) |
| `CognitoClientId` | Cognito App Client ID | Web build (`NEXT_PUBLIC_COGNITO_CLIENT_ID`) |
| `FileBucketName` | S3 file storage bucket name | API deployment |
| `WebBucketName` | S3 web hosting bucket name | Web deployment |
| `DatabaseEndpoint` | RDS endpoint address | Database migrations |
| `DeployBucketName` | S3 deployment bucket name | API deployment |
| `WorkerLambdaName` | Worker Lambda function name | API deployment |

## Infrastructure Deployment

See [Deploying the API](https://alliancebioversityciat-alliance-risk-analysis-tool.mintlify.site/deployment/deploying-api.md) and [Deploying the Web App](https://alliancebioversityciat-alliance-risk-analysis-tool.mintlify.site/deployment/deploying-web.md) for application deployment.

For infrastructure deployment:

```bash theme={null}
cd infra
pnpm cfn:deploy dev   # dev | staging | production
```

See `infra/CLAUDE.md` for CDK vs CloudFormation deployment options.

## Cost Optimization

* **ARM64 Architecture:** 20% cost reduction on Lambda
* **HTTP API:** Cheaper than REST API Gateway (\~70% savings)
* **Gateway VPC Endpoint for S3:** No data transfer charges (vs interface endpoint)
* **CloudFront Price Class 100:** Cheaper edge locations (North America + Europe)
* **Single-AZ RDS:** No multi-AZ replication charges (acceptable for MVP)
* **gp3 Storage:** Better price/performance than gp2

## Security Best Practices

* **Secrets Manager:** Database credentials never hardcoded
* **VPC Isolation:** RDS has no public internet access
* **S3 Block Public Access:** All buckets private by default
* **Encryption at Rest:** RDS and S3 encrypted
* **Encryption in Transit:** HTTPS only for all services
* **Least Privilege IAM:** Lambda roles grant only required permissions
* **CloudFront OAI:** S3 bucket accessible only via CloudFront
* **Security Groups:** Database accessible only from Lambda functions

## Disaster Recovery

* **RDS Automated Backups:** 7-day retention
* **RDS Deletion Policy:** Snapshot on stack deletion (production)
* **S3 Versioning:** Disabled (not required for MVP)
* **CloudFormation Drift Detection:** Run `aws cloudformation detect-stack-drift` periodically

## Monitoring and Logging

* **CloudWatch Logs:**
  * `/aws/lambda/alliance-risk-api` — API Lambda logs
  * `/aws/lambda/alliance-risk-worker` — Worker Lambda logs
* **CloudWatch Metrics:**
  * Lambda invocations, errors, duration, throttles
  * API Gateway 4xx/5xx errors, latency
  * RDS CPU, storage, connections
* **X-Ray Tracing:** Not enabled (optional enhancement)

See CloudWatch Logs for troubleshooting Lambda errors.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.