193 lines
5.6 KiB
Markdown
193 lines
5.6 KiB
Markdown
# Serverless TypeScript Project
|
|
|
|
This folder contains AWS Lambda functions deployed via the Serverless Framework, written in TypeScript.
|
|
|
|
## Setup
|
|
|
|
This project is configured with TypeScript, ESLint, and Prettier independently from the main project.
|
|
|
|
### Prerequisites
|
|
|
|
- Node.js 22.x or higher
|
|
- npm or yarn
|
|
|
|
### Installation
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
## Development
|
|
|
|
### Available Scripts
|
|
|
|
- `npm run build` - Compile TypeScript to JavaScript
|
|
- `npm run type-check` - Run TypeScript type checking without emitting files
|
|
- `npm run lint` - Run ESLint on TypeScript files
|
|
- `npm run lint:fix` - Run ESLint with auto-fix
|
|
- `npm run format` - Format code with Prettier
|
|
- `npm run format:check` - Check if code is formatted correctly
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
src/
|
|
handlers/ # Lambda function handlers
|
|
vehicleType.ts # Vehicle type lookup handler
|
|
scrub.ts # Estimate scrubbing handler
|
|
emsupload.ts # File upload presigned URL handler
|
|
lib/ # Shared library code
|
|
vehicleTypes/ # Vehicle type utilities
|
|
db.ts # Database utilities
|
|
```
|
|
|
|
## Deployment
|
|
|
|
The project uses `serverless-esbuild` for bundling TypeScript code for deployment.
|
|
|
|
```bash
|
|
# 1) Deploy shared infra (VPC + DB + Proxy + Secret) once
|
|
sls deploy --config serverless.infra.yml --stage shared
|
|
|
|
# 2) Deploy the application Lambdas per stage (dev/alpha/beta/prod)
|
|
sls deploy --stage dev
|
|
sls deploy --stage prod
|
|
```
|
|
|
|
## RDS + Drizzle (Postgres)
|
|
|
|
This project provisions a **shared private** Postgres RDS instance (one DB for all app stages) and the networking needed for Lambdas to reach it.
|
|
|
|
If you want direct access from your laptop, the infra stack also allows inbound Postgres from a single admin IP CIDR (default is the current value in `serverless.infra.yml`).
|
|
|
|
### What gets created
|
|
|
|
Defined in `serverless.infra.yml`:
|
|
|
|
- A dedicated VPC with 2 public subnets + 2 private subnets
|
|
- A NAT Gateway for private-subnet egress
|
|
- Security groups:
|
|
- Lambda SG (egress all)
|
|
- RDS Proxy SG (allows inbound `5432` only from the Lambda SG)
|
|
- RDS SG (allows inbound `5432` only from the Proxy SG)
|
|
- An RDS Postgres instance:
|
|
- `DeletionProtection: true`
|
|
- `DeletionPolicy: Snapshot` / `UpdateReplacePolicy: Snapshot`
|
|
- `AutoMinorVersionUpgrade: true` (minor updates)
|
|
- Publicly accessible (restricted to a single `admin_cidr`)
|
|
- An RDS Proxy in the same VPC (Lambdas connect to the proxy, proxy connects to RDS)
|
|
- A Secrets Manager secret for the RDS master user (generated password)
|
|
|
|
Note: RDS + NAT Gateway incur AWS costs.
|
|
|
|
### Direct DB access (your IP only)
|
|
|
|
Infra config includes an `admin_cidr` parameter (e.g. `70.36.57.88/32`) that is allowed to connect to port `5432`. The RDS instance is placed in public subnets so it can be reached directly, but security groups restrict it to that single CIDR.
|
|
|
|
To change it, edit `stages.shared.params.admin_cidr` in `serverless.infra.yml` and redeploy infra:
|
|
|
|
```bash
|
|
cd serverless
|
|
sls deploy --config serverless.infra.yml --stage shared
|
|
```
|
|
|
|
### Drizzle files
|
|
|
|
- Schema: `src/db/schema/**/*.ts`
|
|
- Drizzle config: `drizzle.config.ts`
|
|
- Generated migrations (SQL): `drizzle/` (packaged for Lambda)
|
|
|
|
### Install deps
|
|
|
|
```bash
|
|
cd serverless
|
|
npm install
|
|
```
|
|
|
|
### Generate a migration (no DB connection required)
|
|
|
|
Drizzle can generate SQL migrations by diffing your schema files.
|
|
|
|
```bash
|
|
cd serverless
|
|
npm run db:generate
|
|
```
|
|
|
|
This writes SQL into `serverless/drizzle/`.
|
|
|
|
### Deploy the database
|
|
|
|
```bash
|
|
cd serverless
|
|
sls deploy --config serverless.infra.yml --stage shared
|
|
```
|
|
|
|
RDS creation can take several minutes.
|
|
|
|
### Apply migrations (recommended: run inside AWS)
|
|
|
|
Because the RDS instance is in private subnets, it is not directly reachable from your laptop by default.
|
|
The repo includes an internal migration Lambda (`dbMigrate`) that runs in the same VPC as the database.
|
|
|
|
```bash
|
|
cd serverless
|
|
sls invoke -f dbMigrate --stage dev
|
|
```
|
|
|
|
### Sanity check connectivity
|
|
|
|
```bash
|
|
cd serverless
|
|
sls invoke -f dbPing --stage dev
|
|
```
|
|
|
|
### Local migrations (optional)
|
|
|
|
If you set up network access to the private RDS instance (e.g., via Client VPN or an SSM tunnel through a bastion host), you can run Drizzle migrations locally:
|
|
|
|
```bash
|
|
export DATABASE_URL='postgres://USER:PASSWORD@HOST:5432/esdp'
|
|
npm run db:migrate
|
|
```
|
|
|
|
### Deletion protection behavior
|
|
|
|
- `sls remove --config serverless.infra.yml --stage shared` will **not** be able to delete the DB instance while deletion protection is enabled.
|
|
- To intentionally remove it later, you must first disable deletion protection in `serverless.infra.yml` and redeploy, then remove the infra stack.
|
|
|
|
### Single shared DB
|
|
|
|
The DB name comes from the `shared` stage param `db_name` in `serverless.infra.yml` (defaults to `esdp`). All app stages connect to this same DB via CloudFormation outputs.
|
|
|
|
## Local Development
|
|
|
|
```bash
|
|
# Run serverless offline
|
|
sls dev
|
|
```
|
|
|
|
## Configuration
|
|
|
|
- **TypeScript**: Configured in `tsconfig.json`
|
|
- **ESLint**: Configured in `eslint.config.mjs` (ESM flat config)
|
|
- **Prettier**: Configured in `.prettierrc.json`
|
|
- **Serverless (app)**: Configured in `serverless.yml`
|
|
- **Serverless (infra)**: Configured in `serverless.infra.yml`
|
|
|
|
## Code Quality
|
|
|
|
This project enforces:
|
|
- TypeScript strict mode
|
|
- ESLint rules for TypeScript
|
|
- Prettier formatting
|
|
- No unused variables or parameters (except those prefixed with `_`)
|
|
|
|
## Environment Variables
|
|
|
|
See `serverless.yml` for environment-specific configuration.
|
|
|
|
|
|
How To Deploy
|
|
|
|
Deploy infra once (shared DB + networking): cd serverless && sls deploy --config serverless.infra.yml --stage shared
|
|
Deploy/update Lambdas per environment without touching DB/VPC: cd serverless && sls deploy --stage dev (and similarly --stage prod, etc.) |