Skip to main content

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.ts for a stack named MyStack
  • Place stack files in the lib directory (no subdirectories)
  • Always import Stack from @root/aws-cdk-lib, never directly from aws-cdk-lib

CDK Stack Coding Conventions

  • Use cdk-nag to enforce best practices and security checks.
  • Use cdk-assert for 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:

  1. Identify the aws-cdk-lib module (e.g., aws-cdk-lib/aws-ssm)
  2. Create matching folder in src-extends-aws-cdk-lib/ (e.g., src-extends-aws-cdk-lib/aws-ssm/)
  3. Create extended class file matching AWS class name (e.g., StringParameter.ts)
  4. Export from folder index.ts and root src-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:

  1. Create resource-type folder: lib/{resourceType}/ (e.g., lib/stringParameter/)
  2. Use camelCase for folder names
  3. File name must match the Construct class name in PascalCase
  4. Make all AWS resources public readonly properties for Stack access
  5. 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 from aws-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 test directory
  • Always use the NodeJSFunction construct from AWS CDK
  • Specify runtime as Runtime.NODEJS_22_X
  • API methods for example: ['GET', 'POST', 'PUT', 'DELETE'] should be in a single lambdas