# {{STACK_NAME}} CDK Infrastructure

This directory contains the AWS CDK infrastructure code for deploying {{STACK_NAME}} to AWS.

## Overview

The CDK app uses the declarative infrastructure API framework from `@worktif/runtime/infra` to provision all required AWS resources:

- **S3 Bucket**: Stores static assets and cached SSR responses
- **Lambda Functions**: Handle server-side rendering and API endpoints
- **CloudFront Distribution**: CDN for global content delivery
- **DynamoDB Table**: (Optional) Stores SEO metadata when `enableSeo` is true
- **IAM Roles**: Least-privilege permissions for Lambda execution

## Directory Structure

```
cdk/
├── bin/
│   └── app.ts              # Minimal entry point (~50 lines)
├── lib/
│   ├── config.ts           # Shared configuration
│   ├── infra-stack.ts      # RuntimeInfraStack configuration
│   ├── runtime-stack.ts    # RuntimeStack (SSR) configuration
│   ├── web-stack.ts        # RuntimeWebStack (microservices) configuration
│   └── awake-stack.ts      # RuntimeAwakeStack (dev only) configuration
├── cdk.json
├── package.json
├── tsconfig.json
└── README.md
```

### Stack Configuration Files

| File | Purpose |
|------|---------|
| `lib/config.ts` | Centralized configuration with stage-specific defaults |
| `lib/infra-stack.ts` | Base infrastructure (S3, DynamoDB, IAM) using declarative API |
| `lib/runtime-stack.ts` | SSR Lambda configuration |
| `lib/web-stack.ts` | Microservices Lambda configuration |
| `lib/awake-stack.ts` | Runtime Lambda Debug (dev stage only) |

## Prerequisites

1. **AWS CLI**: Install and configure AWS CLI with your credentials
   ```bash
   aws configure
   ```

2. **Node.js**: Version 18 or higher

3. **AWS CDK**: Install globally (optional, can use npx)
   ```bash
   npm install -g aws-cdk
   ```

## Getting Started

**Good news!** If you initialized this CDK app using `runtime init`, all dependencies have already been installed automatically. You can skip directly to deployment!

### 1. Verify Installation (Already Done!)

During initialization, Runtime Web automatically:
- ✓ Installed all project dependencies (React, Runtime Web, etc.)
- ✓ Installed all CDK dependencies (aws-cdk-lib, constructs, etc.)
- ✓ Validated that all packages are correctly installed

If you need to reinstall dependencies manually:

```bash
# Install project dependencies (from project root)
cd ..
npm install

# Install CDK dependencies
cd cdk
npm install
```

### 2. Bootstrap CDK (First Time Only)

Bootstrap provisions the CDK toolkit resources in your AWS account:

```bash
cdk bootstrap
```

This only needs to be done once per AWS account/region combination.

**Note**: If you chose to run bootstrap during initialization, this step is already complete!

### 3. Deploy Infrastructure

Deploy to the default stage (dev):

```bash
cdk deploy --all
```

Deploy to a specific stage:

```bash
npm run deploy:dev      # Deploy to dev
npm run deploy:staging  # Deploy to staging
npm run deploy:prod     # Deploy to prod
```

### 4. View Deployment Outputs

After deployment, CDK will display important outputs:

- **CloudFront URL**: Your application's public URL
- **S3 Bucket Name**: Where static assets are stored
- **Lambda Function ARN**: The SSR handler function

## Configuration

### Shared Configuration (lib/config.ts)

The `lib/config.ts` file centralizes all stack configuration:

```typescript
import { getConfig } from './lib/config';

const config = getConfig('dev');
// config.stage: 'dev' | 'staging' | 'prod'
// config.serviceName: Sanitized service name
// config.enableSeo: Enable SEO features
// config.enableAwake: Enable Runtime Lambda Debug
// config.env: AWS account and region
// config.stageDefaults: Stage-specific defaults (removal policy, encryption, etc.)
```

### Infrastructure Stack (lib/infra-stack.ts)

The infrastructure stack uses the declarative infrastructure API:

```typescript
import {
    createInfrastructureContext,
    createResourceFacade,
    createExtendedStackIntegration,
} from '@worktif/runtime/infra';

// Create Infrastructure Context (Aggregate Root)
const context = createInfrastructureContext({
    infraStack: stack,
    serviceName: config.serviceName,
    stage: config.stage,
});

// Create Resource Facade for simplified resource creation
const facade = createResourceFacade(config.serviceName, config.stage);

// Create Stack Integration for cross-stack references
const integration = createExtendedStackIntegration(stack, stack);
```

## Using the Declarative Infrastructure API

### Creating Resources with ResourceFacade

The `ResourceFacade` provides simplified resource creation with stage-appropriate defaults:

```typescript
// Create DynamoDB table
const usersTable = facade.createStandardTable('users', 'userId');

// Create SQS queue (includes dead-letter queue)
const ordersQueue = facade.createStandardQueue('orders');

// Create SNS topic
const notificationsTopic = facade.createStandardTopic('notifications');

// Create S3 bucket (includes versioning and encryption)
const uploadsBucket = facade.createStandardBucket('uploads');

// Create Cognito User Pool
const authPool = facade.createStandardUserPool('auth');

// Create EventBridge Event Bus
const eventBus = facade.createStandardEventBus('events');
```

### Creating Resources with Factories

For full CDK props access, use factories:

```typescript
const dynamoFactory = context.factories.get('dynamodb');
if (dynamoFactory) {
    const ordersTable = dynamoFactory.createTable('orders', {
        partitionKey: { name: 'orderId', type: dynamodb.AttributeType.STRING },
        sortKey: { name: 'timestamp', type: dynamodb.AttributeType.NUMBER },
        billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
        stream: dynamodb.StreamViewType.NEW_AND_OLD_IMAGES,
    });
}
```

### Using Builders for Fluent Configuration

Builders provide fluent configuration with validation:

```typescript
const dynamoFactory = context.factories.get('dynamodb');
if (dynamoFactory) {
    const builder = dynamoFactory.getBuilder('analytics');
    const analyticsTable = builder
        .withProps({
            partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
            sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING },
        })
        .withAutoGrant(true)
        .withAutoInject({
            envVarName: 'ANALYTICS_TABLE',
            includeArn: true,
            includeName: true,
        })
        .withTags({ Team: 'Analytics', Cost: 'data-analytics' })
        .build();
}
```

### Registering Decorators

Decorators apply cross-cutting concerns to all resources:

```typescript
// Apply consistent tags to all resources
context.decorators.register(new TaggingDecorator({
    tags: {
        Project: config.serviceName,
        Stage: config.stage,
        ManagedBy: 'DeclarativeInfrastructureAPI',
    },
    includeDefaults: true,
}));
```

### Registering Observers

Observers automatically grant permissions and inject environment variables:

```typescript
// Automatically grant IAM permissions to Lambda roles
context.observers.register(new AutoGrantObserver('auto-grant', {
    roleArn: stack.lambdaRole.roleArn,
    permissionLevel: 'full',
}));
```

## Multiple Stages

The configuration automatically handles stage-specific defaults:

| Stage | Removal Policy | Encryption | PITR |
|-------|---------------|------------|------|
| dev | DESTROY | Optional | No |
| staging | SNAPSHOT | Yes | Yes |
| prod | RETAIN | Yes | Yes |

Deploy to different stages:

```bash
# Deploy to dev
cdk deploy --all --context stage=dev

# Deploy to staging
cdk deploy --all --context stage=staging

# Deploy to production
cdk deploy --all --context stage=prod
```

## Useful Commands

- `npm run build`: Compile TypeScript to JavaScript
- `npm run watch`: Watch for changes and compile
- `cdk synth`: Synthesize CloudFormation template
- `cdk diff --all`: Compare deployed stack with current state
- `cdk deploy --all`: Deploy stack to AWS
- `cdk destroy`: Remove all resources (use with caution!)

## Troubleshooting

### "Unable to resolve AWS account"

**Problem**: CDK can't determine your AWS account ID.

**Solution**: Set environment variables or configure AWS CLI:
```bash
# Option 1: Set environment variables
export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
export AWS_REGION={{REGION}}

# Option 2: Configure AWS CLI (recommended)
aws configure set region {{REGION}}
```

### "Stack already exists"

**Problem**: A stack with the same name already exists.

**Solution**: CDK will update the existing stack. Use `cdk diff` to preview changes.

### "Insufficient permissions"

**Problem**: Your AWS credentials don't have required permissions.

**Solution**: Ensure your IAM user/role has permissions for:
- CloudFormation
- S3
- Lambda
- CloudFront
- DynamoDB (if enableSeo is true)
- IAM (for creating roles)

### "Lambda bundle not found"

**Problem**: The Lambda bundle hasn't been built.

**Solution**: Build your Runtime Web application first:
```bash
cd ..
npm run build
cd cdk
cdk deploy --all
```

### "Dependencies not installed"

**Problem**: CDK dependencies are missing or corrupted.

**Solution**:

If you initialized with `runtime init`, dependencies should already be installed. If you're experiencing issues:

```bash
# Reinstall project dependencies
cd ..
rm -rf node_modules package-lock.json
npm install

# Reinstall CDK dependencies
cd cdk
rm -rf node_modules package-lock.json
npm install
```

## Learn More

- [AWS CDK Documentation](https://docs.aws.amazon.com/cdk/)
- [Runtime Web Documentation](https://runtimeweb.com/docs/getting-started)
- [Declarative Infrastructure API Reference](https://runtimeweb.com/docs/cdk/declarative-api)
- [RuntimeInfraStack API Reference](https://runtimeweb.com/docs/cdk)
