What you’ll learn: TypeScript (typed JavaScript), AWS CDK (infrastructure as code), and how EPICBackendCDK works.
Prerequisite: Read Guide 01 (JavaScript Basics) first.


Section 1 β€” What Is TypeScript?

TypeScript is JavaScript with type checking added. The browser/Node.js doesn’t run TypeScript directly β€” it gets compiled to JavaScript first.

Why use it? Catches bugs before runtime. In a large codebase like EPIC, this is crucial.

// JavaScript (no type checking)
function calculateHosts(peakTpm, ctFactor, bufferFactor) {
    return peakTpm / (ctFactor * bufferFactor);  // what if someone passes "hello"?
}

// TypeScript (with type checking)
function calculateHosts(peakTpm: number, ctFactor: number, bufferFactor: number): number {
    return peakTpm / (ctFactor * bufferFactor);  // TypeScript would catch wrong types
}
calculateHosts("hello", 1.2, 1.1);  // ERROR at compile time!

Section 2 β€” TypeScript Types

// Basic types
const fleetId: string = "RIPE-NA";
const peakTpm: number = 50000;
const isEmergent: boolean = false;
const maybeTpm: number | null = null;  // either a number or null

// Arrays
const fleetIds: string[] = ["RIPE-NA", "RIPE-EU"];
const tpmValues: number[] = [50000, 30000];

// Object type (interface)
interface Fleet {
    FleetId: string;
    ServiceId: string;
    PeakTPM: number;
    Region: string;
    IsEmergent?: boolean;  // ? means optional
}

const fleet: Fleet = {
    FleetId: "RIPE-NA",
    ServiceId: "RIPE",
    PeakTPM: 50000,
    Region: "us-east-1"
};

// Function type
type CalculatorFn = (a: number, b: number) => number;
const add: CalculatorFn = (a, b) => a + b;

Section 3 β€” TypeScript Interfaces (Used Extensively in CDK)

Interfaces define the β€œshape” of props passed to CDK stacks:

// From HOTWLambdaStack.ts
export interface HOTWLambdaStackProps {
    readonly stage: string;
    readonly env: DeploymentEnvironment;
    readonly stackName?: string;      // optional (?)
    readonly vpc: IVpc;               // VPC interface from CDK
    readonly serviceTable: ITable;    // DynamoDB table
    readonly fleetTable: ITable;
    readonly eventTable: ITable;
    readonly eventPlanTable: ITable;
    readonly notificationSNS: ITopic; // SNS topic
    readonly emailQueue: IQueue;      // SQS queue
    // ...
}

Why readonly? These props should not be modified once passed to the stack.


Section 4 β€” What Is AWS CDK?

AWS CDK (Cloud Development Kit) lets you define cloud infrastructure using code instead of clicking in the AWS console or writing YAML files.

Without CDK (manual way):

  1. Go to AWS Console
  2. Click β€œCreate Lambda Function”
  3. Fill in name, runtime, memory, etc.
  4. Click β€œCreate DynamoDB table”
  5. Set keys, GSIs, etc.
  6. Repeat 100+ times for every service

With CDK:

// Define everything in code β€” repeatable, versionable, reviewable
const myLambda = new Function(this, 'MyLambda', {
    handler: 'handler.HOTW.getHotwDashboardDetails',
    runtime: Runtime.NODEJS_16_X,
    timeout: Duration.seconds(300),
    memorySize: 512,
});

CDK code gets β€œsynthesized” (compiled) into AWS CloudFormation templates, which then create the actual cloud resources.


Section 5 β€” CDK Stacks: The Core Concept

A Stack is a group of AWS resources that are deployed and managed together.

class HOTWLambdaStack extends DeploymentStack {
    // Properties declared on the class
    public readonly getHotwDashboardDetailsLambda: Function;
    public readonly hotwApi: RestApi;
    
    constructor(parent: App, name: string, props: HOTWLambdaStackProps) {
        super(parent, name, { ... });
        
        // Create resources in the constructor
        this.hotwApi = new RestApi(this, 'HOTWApi', { ... });
        
        this.getHotwDashboardDetailsLambda = this.createLambda(
            "getHotwDashboardDetailsLmda",
            "handler.HOTW.getHotwDashboardDetails",
            props
        );
    }
    
    private createLambda(name: string, handler: string, props: HOTWLambdaStackProps): Function {
        return new Function(this, name, {
            code: LambdaAsset.fromBrazil({
                brazilPackage: BrazilPackage.fromString('EPICBackend-1.0'),
                componentName: 'EPICBackend'
            }),
            handler,
            timeout: Duration.seconds(300),
            memorySize: 512,
            runtime: Runtime.NODEJS_16_X,
            vpc: this.vpc,
            environment: {
                FLEET_TABLE_NAME: props.fleetTable.tableName,
                EVENT_TABLE_NAME: props.eventTable.tableName,
            }
        });
    }
}

Section 6 β€” All EPIC CDK Stacks

The EPIC infrastructure is split into many stacks, each in its own file:

Stack File What It Creates
app.ts Entry point β€” instantiates all stacks
apiStack.ts DynamoDB tables, SQS queues, SNS topics
vpcStack.ts Virtual Private Cloud networking
HOTW/HOTWLambdaStack.ts HOTW Lambda functions + API Gateway
Fleet/fleetLambdaStack.ts Fleet CRUD Lambda functions
Service/serviceLambdaStack.ts Service CRUD Lambda functions
Event/eventLambdaStack.ts Event CRUD Lambda functions
EventPlan/eventPlanLambdaStack.ts EventPlan CRUD Lambda functions
Projections/projectionsLambdaStack.ts Projections Lambda functions
triggersStack.ts Java Lambda triggers (HOTW, Apollo, etc.)
apolloStack.ts Apollo integration Lambda
fmcStack.ts FMC hardware order Lambda
throttlingStack.ts Throttling Lambda
milestoneWorkflowStack.ts Milestone workflow Lambda
bauScalingStack.ts BAU scaling Lambda
scalingPlannerStack.ts ScalingPlanner integration
simStack.ts SIM ticket Lambda
axonStack.ts Axon traffic data Lambda
pmetStack.ts PMET metrics Lambda
resilienceStack.ts Resilience data Lambda
EmailTemplates/ HTML email templates (TypeScript strings)
Monitors/ CloudWatch alarms and metrics

Section 7 β€” Key CDK Resources Explained

Lambda Functions

new Function(this, 'uniqueId', {
    code: LambdaAsset.fromBrazil({          // code comes from Brazil build system
        brazilPackage: BrazilPackage.fromString('EPICBackend-1.0'),
        componentName: 'EPICBackend'
    }),
    handler: 'handler.HOTW.getHotwDashboardDetails', // file.class.method
    timeout: Duration.seconds(300),                    // max 5 min to run
    memorySize: 512,                                   // 512 MB RAM
    runtime: Runtime.NODEJS_16_X,                      // Node.js 16
    vpc: this.vpc,                                     // VPC for security
    environment: {                                     // env vars inside Lambda
        FLEET_TABLE_NAME: props.fleetTable.tableName,
    }
});

What handler means: handler.HOTW.getHotwDashboardDetails

  • handler = folder name
  • HOTW = file name (HOTW.js)
  • getHotwDashboardDetails = method name

DynamoDB Tables

// From apiStack.ts (simplified)
const fleetTable = new Table(this, 'FleetTable', {
    partitionKey: { name: 'FleetId', type: AttributeType.STRING },    // PK
    sortKey: { name: 'VersionId', type: AttributeType.NUMBER },       // SK
    billingMode: BillingMode.PAY_PER_REQUEST,
    stream: StreamViewType.NEW_AND_OLD_IMAGES,  // triggers Lambda on change
});

SQS Queues

// Standard queue
const apolloQueue = new Queue(this, 'ApolloSQSQueue', {
    queueName: 'ApolloSQSQueue',
    visibilityTimeout: Duration.seconds(300),
});

// FIFO queue (ordered, exactly-once delivery)
const atomicHotwQueue = new Queue(this, 'atomicHOTWSQSQueue', {
    queueName: 'atomicHOTWSQSQueue.fifo',  // .fifo suffix required!
    fifo: true,
    contentBasedDeduplication: true,
    deadLetterQueue: {
        queue: atomicHotwDLQ,              // failed messages go here
        maxReceiveCount: 3,
    }
});

SNS Topics

const milestoneSNS = new Topic(this, 'MilestoneSNSTopic', {
    topicName: 'MilestoneSNSTopic',
});
// Lambda can subscribe to this topic:
milestoneSNS.addSubscription(new LambdaSubscription(hotwHandler));

IAM Permissions

// Give Lambda permission to READ DynamoDB table
props.fleetTable.grantReadData(this.getHotwDashboardDetailsLambda);

// Give Lambda permission to READ+WRITE DynamoDB table
props.fleetTable.grantReadWriteData(this.createOrUpdateHotwRunDetailsLambda);

// Give Lambda permission to publish to SNS
lambdaFunction.addToRolePolicy(new PolicyStatement({
    effect: Effect.ALLOW,
    actions: ["sns:Publish"],
    resources: [props.notificationSNS.topicArn]
}));

Section 8 β€” Constants.ts: All Queue and Topic Names

lib/constants.ts is a critical file β€” it defines all the names of AWS resources:

// SQS Queue names
export const HOTW_Audit_SQS_QUEUE = "HotwAuditSQSQueue.fifo";
export const VALIDATE_UPDATE_SPCO_SQS_QUEUE = "validateAndUpdateSPCOSQSQueue.fifo";
export const ATOMIC_HOTW_SQS_QUEUE = "atomicHOTWSQSQueue.fifo";
export const APOLLO_SQS_QUEUE = "ApolloSQSQueue";
export const FMC_SQS_QUEUE = "FmcSQSQueue.fifo";
export const MILESTONE_SQS_QUEUE = "MilestoneSQSQueue.fifo";

// SNS Topic names
export const MILESTONE_SNS_TOPIC_NAME = "MilestoneSNSTopic";
export const TICKETING_READINESS_SNS_TOPIC_NAME = "TicketingReadinessSNSTopic";

// DynamoDB table names
export const FLEET_LOCK_TABLE = "FleetLockTable";

These names MUST match between CDK (where queues/topics are created) and Java code (where they are referenced by name).


Section 9 β€” Email Templates

EPIC sends automated emails. Templates are defined in TypeScript as template literals:

// lib/EmailTemplates/hardwareOrderDetails.html.ts
export const hardwareOrderDetailsHtml = `
<!DOCTYPE html>
<html>
<head><title>Hardware Order Details</title></head>
<body>
    <h2>HOTW Hardware Order Summary</h2>
    <p>Fleet: {{FleetId}}</p>
    <p>Hosts Ordered: {{HostsOrdered}}</p>
    <p>Peak TPM: {{PeakTPM}}</p>
    <table>
        <!-- order details table -->
    </table>
</body>
</html>
`;

Templates available in EPIC:

  • hardwareOrderDetails.html.ts β€” HOTW order details email
  • gatherProjections.html.ts β€” reminder to fill in projections
  • peakReadinessReport.html.ts β€” readiness report for leaders
  • bauReminderForService.html.ts β€” BAU capacity reminder
  • createService.html.ts β€” new service onboarding notification
  • descalingSpcoDetails.html.ts β€” descale order details

Section 10 β€” CloudWatch Monitors

// lib/Monitors/Constants/alarmConstants.ts
// Defines alarm names and thresholds

// lib/Monitors/Constants/metricConstants.ts
// Defines custom CloudWatch metric names

// lib/Monitors/monitorsShared.ts
// Creates CloudWatch alarms for Lambda errors, duration, etc.

Alarms notify the team if:

  • Lambda error rate exceeds threshold
  • Lambda duration is too high
  • SQS queue depth grows too large

Section 11 β€” Environments in EPIC CDK

EPIC has three environments:

BETA β†’ for development testing
GAMMA β†’ for integration testing  
PROD β†’ production (what customers use)

Each gets its own account and stack:

// From constants.ts
export const HARMONY_ACCOUNT_BETA = "357229612043";
export const HARMONY_ACCOUNT_GAMMA = "527104685944";
export const HARMONY_ACCOUNT_PROD_IAD = "608894314745";
export const HARMONY_ACCOUNT_PROD_PDX = "569058367367";
export const HARMONY_ACCOUNT_PROD_DUB = "255384666509";

Section 12 β€” Brazil Build System

EPIC uses Amazon’s internal build system called Brazil (not standard npm/Maven):

# Brazil commands (you'll use these at Amazon)
brazil setup workspace             # initialize workspace
brazil build                       # build all packages
brazil ws sync -md EPICBackendCDK  # sync a specific package

In CDK code, Lambda code is referenced through Brazil:

code: LambdaAsset.fromBrazil({
    brazilPackage: BrazilPackage.fromString('EPICBackend-1.0'),
    componentName: 'EPICBackend'
})
// This tells CDK: "get the Lambda code from the EPICBackend Brazil package"

Section 13 β€” How to Read a CDK Stack File

When you see a CDK stack file, read it in this order:

  1. Interface β€” what parameters this stack needs
  2. Public fields β€” what resources this stack exposes to other stacks
  3. Constructor β€” where all resources are created
  4. Private helper methods β€” reusable resource creation patterns

Example walkthrough of HOTWLambdaStack.ts:

// Step 1: Read the interface β€” what does this stack need as inputs?
export interface HOTWLambdaStackProps {
    readonly vpc: IVpc;              // needs a VPC
    readonly fleetTable: ITable;     // needs DynamoDB fleet table
    readonly eventTable: ITable;     // needs DynamoDB event table
    // ...
}

// Step 2: Public fields β€” what does this stack give to others?
public readonly hotwApi: RestApi;                          // exposes the API
public readonly getHotwDashboardDetailsLambda: Function;   // exposes lambdas

// Step 3: Constructor β€” what gets created?
constructor(...) {
    this.hotwApi = new RestApi(this, 'HOTWApi', { ... });    // REST API created here
    this.getHotwDashboardDetailsLambda = this.createLambda(  // Lambda created here
        "getHotwDashboardDetailsLmda",
        "handler.HOTW.getHotwDashboardDetails",
        props
    );
    props.fleetTable.grantReadData(this.getHotwDashboardDetailsLambda);  // IAM permission
}

// Step 4: Helper β€” how are Lambdas created?
private createLambda(name, handler, props): Function {
    return new Function(this, name, { handler, ... });
}

Section 14 β€” Quick Reference

TypeScript Meaning Example
string Text type const name: string = "EPIC"
number Numeric type const tpm: number = 50000
boolean True/false const ready: boolean = true
T[] Array of T const ids: string[] = []
T | null T or null const maybe: string | null = null
? in interface Optional field readonly name?: string
readonly Can’t be changed readonly stage: string
interface Object shape interface Props { id: string }
export Make available export class MyStack { }
import Use from other file import { Stack } from 'cdk'
CDK Resource Code What it creates
Lambda new Function(...) Serverless function
DynamoDB Table new Table(...) NoSQL database table
SQS Queue new Queue(...) Message queue
SNS Topic new Topic(...) Pub/sub notifications
API Gateway new RestApi(...) HTTP REST API
VPC new Vpc(...) Private network
IAM Role new Role(...) Access permissions
CloudWatch Alarm new Alarm(...) Alert when threshold crossed