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):
- Go to AWS Console
- Click βCreate Lambda Functionβ
- Fill in name, runtime, memory, etc.
- Click βCreate DynamoDB tableβ
- Set keys, GSIs, etc.
- 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 nameHOTW= 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 emailgatherProjections.html.tsβ reminder to fill in projectionspeakReadinessReport.html.tsβ readiness report for leadersbauReminderForService.html.tsβ BAU capacity remindercreateService.html.tsβ new service onboarding notificationdescalingSpcoDetails.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:
- Interface β what parameters this stack needs
- Public fields β what resources this stack exposes to other stacks
- Constructor β where all resources are created
- 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 |