Backend
Backend
TypeScript Types
- Shared TypeScript types are defined in
shared/models/. - All TypeScript types should be defined in
shared/models/.
CDK Stacks
- Auth Stack: Manages user authentication with AWS Cognito and Clerk.
- API Stack: Sets up the API Gateway, Lambda functions, and DynamoDB tables.
- Frontend Stack: Deploys the React application to S3 and configures CloudFront for CDN.
- Email Stack: Configures AWS SES for email notifications.
- Each CDK Stack must be in its own file
- File name must match the stack name in PascalCase format
- Example:
MyStack.tsfor a stack namedMyStack - Place stack files in the
libdirectory (no subdirectories) - Always import Stack from
@root/aws-cdk-lib, never directly fromaws-cdk-lib
CDK Stack Coding Conventions
- Use
cdk-nagto enforce best practices and security checks. - Use
cdk-assertfor unit testing CDK stacks. - Never hardcode sensitive information like API keys or secrets in the codebase.
- Never Use cdk outputs to link resources across stacks. Instead, use ssm parameters.
CDK Constructs - Two-Step Pattern
Step 1: Extend aws-cdk-lib Base Class (src-extends-aws-cdk-lib/)
BEFORE creating any resource Construct, extend the base aws-cdk-lib class first:
- Identify the aws-cdk-lib module (e.g.,
aws-cdk-lib/aws-ssm) - Create matching folder in
src-extends-aws-cdk-lib/(e.g.,src-extends-aws-cdk-lib/aws-ssm/) - Create extended class file matching AWS class name (e.g.,
StringParameter.ts) - Export from folder
index.tsand rootsrc-extends-aws-cdk-lib/index.ts
Example: src-extends-aws-cdk-lib/aws-ssm/StringParameter.ts
import { StringParameter as AwsStringParameter, StringParameterProps } from 'aws-cdk-lib/aws-ssm';
import { Construct } from 'constructs';
export class StringParameter extends AwsStringParameter {
constructor(scope: Construct, id: string, props: StringParameterProps) {
super(scope, id, props);
// Add project-specific defaults here
}
}
Step 2: Create Business Construct (lib/{resourceType}/)
After extended base class exists, create your business construct:
- Create resource-type folder:
lib/{resourceType}/(e.g.,lib/stringParameter/) - Use camelCase for folder names
- File name must match the Construct class name in PascalCase
- Make all AWS resources public readonly properties for Stack access
- Import extended classes from
@root/aws-cdk-lib/*
Example: lib/stringParameter/ConfigParameter.ts
import { Construct } from 'constructs';
import { StringParameter } from '@root/aws-cdk-lib/aws-ssm';
export interface ConfigParameterProps {
readonly parameterName: string;
readonly value: string;
}
export class ConfigParameter extends Construct {
public readonly parameter: StringParameter;
constructor(scope: Construct, id: string, props: ConfigParameterProps) {
super(scope, id);
this.parameter = new StringParameter(this, 'Parameter', {
parameterName: props.parameterName,
stringValue: props.value,
});
}
}
Construct Organization Requirements
- Each AWS resource type in its own
lib/{resourceType}/folder - File name must match Construct class name in PascalCase
- All resources must be public readonly properties
- Must follow standard CDK Construct patterns
- Always import from
@root/aws-cdk-lib/*, never directly fromaws-cdk-lib
Lambda Functions
- Always written in TypeScript
- Organize in
src/lambda/{lambdaName}directories for individual lambdas src/lambda/must be configured as a separate npm workspace- Filename must match the lambda name in camelCase format
- Each lambda must have:
- Its own
package.json - Its own
tsconfig.json - Its own
.gitignore - Jest tests in its own
testdirectory
- Its own
- Always use the
NodeJSFunctionconstruct from AWS CDK - Specify runtime as
Runtime.NODEJS_22_X - API methods for example: ['GET', 'POST', 'PUT', 'DELETE'] should be in a single lambdas