Skip to main content

TypeScript Lambda

sdlcs-aws-cdk-lib

💻 Tech stack​

  • NextJS + Tailwind CSS
  • AWS Serverless (Lambda, API Gateway, DynamoDB, S3)
  • Stripe for billing
  • Auth with Clerk
  • PDF reporting
  • Email notifications with AWS SES
  • Unit and integration tests with Jest
  • CDK Typescript for infrastructure as code
  • GitHub Actions for CI/CD
  • Typescript for type safety
  • ESLint and Prettier for code quality
  • Uses npm workspaces for monorepo structure
  • Node v22.x
  • All code is written in TypeScript
  • Uses AWS CDK for infrastructure
  • Always use the latest version of AWS CDK
  • Node version is specified in the .nvmrc file
  • NPM repositories are configured in the .npmrc file
  • Command line tools are defined in the package.json file

Configuration Files​

  • ESLint: Follow rules specified in .eslintrc.config.mjs for code quality
  • TypeScript: Adhere to compiler options in tsconfig.json
  • Renovate: Dependency updates managed via renovate.json
  • CDK: Reference cdk.json for CDK app settings and context values
  • Git: Honor exclusions in .gitignore
  • Prettier: Code formatting defined in .prettierrc
  • npm: Package access configured in .npmrc
  • GitHub Actions: Workflows configured in .github/workflows/*.yml
  • When modifying any configuration file, ensure to update documentation accordingly

TypeScript​

  • Use strict mode in tsconfig.json
  • Use tsc for type checking
  • Strict Types are defined in the frontend/types directory for both frontend and backend
  • Use interface for defining types
  • Use type for defining unions or complex types
  • Avoid enum — prefer as const objects with derived union types; use enum only when required for interoperability with external libraries
  • Never use Record<string, any> – use typed objects or Record<string, unknown> with narrowing
  • Use unknown for values that can be of any type but need type checking before use
  • Use any only as a last resort when type safety cannot be guaranteed
  • Use never for functions that never return (e.g., throw an error)
  • Use void for functions that do not return a value
  • Use Promise<T> for asynchronous functions that return a value
  • Use Promise<void> for asynchronous functions that do not return a value
  • Use async/await for asynchronous code
  • Use import statements for importing modules
  • Use export statements for exporting modules
  • Prefer named exports over default exports

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_20_X
  • API methods for example: ['GET', 'POST', 'PUT', 'DELETE'] should be in a single lambdas

Workspace Frontend​

Style Consistency​

  • All new product sections must use shared UI components from src/frontend/components/ui where possible.
  • Tailwind CSS configuration is centralized; do not override styles locally unless necessary.
  • Follow the design tokens and UI patterns documented in /docs/frontend/style-guide.md.
  • When adding new UI components, update the style guide and, if using, Storybook stories.
  • Ensure all frontend code is reviewed for visual and interaction consistency with existing sections.

Workspace Shared​

Domain Model Definitions​

  • All domain models (e.g., Building, LedgerEntry, Unit) are defined in shared/models/.
  • Always import types from shared/models in all backend, frontend, and lambda code.
  • Update or refactor model definitions only in this folder.
  • When adding new models, create a new file in shared/models and export from shared/models/index.ts.
  • All models must include an ownerId field for SaaS multi-tenancy. This is assigned at master account creation and used as the subdomain name.
  • All API, DynamoDB, and business logic must scope data by ownerId.
  • On signup, only master accounts are created, requiring a max 40 character valid word for the subdomain. Sub-users can only be invited by the administrator via the users screen.
  • Use Clerk.com organization feature for member management and invitations.
  • Lambda@Edge must augment all API claims with the ownerId from the subdomain.
  • This ensures consistency, easy refactoring, and version control of all domain types and multi-tenant logic.