Skip to content

Commit c986401

Browse files
committed
feat!: migrate to pnpm workspaces monorepo with Aurora DSQL and Drizzle ORM
Replace the single-package npm project with a pnpm workspaces monorepo, migrate from Aurora Serverless v2 + Prisma to Aurora DSQL + Drizzle ORM, and replace ESLint + Prettier with oxlint + oxfmt. Architecture: - apps/webapp (Next.js), apps/async-job (Lambda), apps/cdk (CDK infra) - packages/db (Drizzle schema, DSQL client, migration runner) - packages/shared-types (job payload Zod schemas) Database: - Aurora DSQL with IAM auth (no VPC, no NAT, no Bastion) - Drizzle ORM with relations() for joins (no FK, DSQL constraint) - Custom migration runner: hash verification, 1 DDL/tx, DSQL SQL validation - dsql-migrator CDK Construct: Docker Lambda + CDK Trigger for deploy-time migration Tooling: - oxlint with type-aware linting (oxlint-tsgolint) replaces ESLint + tsc --noEmit - oxfmt with .oxfmtrc.json matching original .prettierrc (singleQuote, printWidth 120) - shamefully-hoist removed; missing implicit deps made explicit Docker: - All Dockerfiles use pnpm install (no --filter) for strict mode compatibility - esbuild bundles to .mjs (Lambda ESM requirement) - IgnoreMode.DOCKER on all Docker assets to read root .dockerignore - Verified: all 3 images build and respond to Lambda RIE invocations Refs: #98, #91, discussion #94
1 parent a463b5c commit c986401

108 files changed

Lines changed: 9180 additions & 20950 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# dependencies (reinstalled inside container)
2+
**/node_modules
3+
4+
# build artifacts
5+
**/.next
6+
apps/cdk/cdk.out
7+
apps/cdk/.cdk.staging
8+
9+
# vcs / ci / editor
10+
.git
11+
.github
12+
.kiro
13+
.playwright-cli
14+
15+
# docs / meta
16+
.serverless-full-stack-webapp-starter-kit
17+
scripts
18+
*.md
19+
LICENSE
20+
CHANGELOG.md

.github/workflows/build.yml

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,23 @@ on:
88
workflow_dispatch:
99
pull_request:
1010
jobs:
11-
Build-and-Test-CDK:
11+
Build-and-Test:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- uses: actions/checkout@v5
1515
- name: Use Node.js
1616
uses: actions/setup-node@v6
1717
with:
1818
node-version: '22.x'
19-
- run: |
20-
npm ci
21-
npm run format:check
22-
working-directory: ./cdk
23-
name: Install dependencies and run static analysis
24-
- run: |
25-
npm run build
26-
npm run test
27-
working-directory: ./cdk
28-
name: build and test
29-
Build-and-Test-Webapp:
30-
runs-on: ubuntu-latest
31-
steps:
32-
- uses: actions/checkout@v5
33-
- name: Use Node.js
34-
uses: actions/setup-node@v6
35-
with:
36-
node-version: '22.x'
37-
- run: |
38-
npm ci
39-
npm run format:check
40-
working-directory: ./webapp
41-
name: Install dependencies and run static analysis
42-
- run: |
43-
cp .env.local.example .env.local
44-
npm run build
45-
working-directory: ./webapp
46-
name: build
19+
- name: Install pnpm
20+
run: corepack enable && corepack prepare pnpm@10.8.1 --activate
21+
- name: Install dependencies
22+
run: pnpm install --frozen-lockfile
23+
- name: Check
24+
run: pnpm run check:ci
25+
- name: Test
26+
run: pnpm run test:unit
27+
- name: Build
28+
run: |
29+
cp apps/webapp/.env.local.example apps/webapp/.env.local
30+
pnpm run build

.github/workflows/update_snapshot.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ jobs:
2525
uses: actions/setup-node@v6
2626
with:
2727
node-version: "22.x"
28+
- name: Install pnpm
29+
run: corepack enable && corepack prepare pnpm@10.8.1 --activate
2830
- run: |
29-
npm ci
30-
npm run test -- -u
31-
working-directory: ./cdk
31+
pnpm install --frozen-lockfile
32+
cd apps/cdk && pnpm run test:unit -u
3233
- name: Add & Commit
3334
uses: EndBug/add-and-commit@v7.2.0
3435
with:
35-
add: "cdk/test/__snapshots__/."
36+
add: "apps/cdk/test/__snapshots__/."
3637
message: "update snapshot"

.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
node_modules
2+
.DS_Store
3+
*.pem
4+
*.tsbuildinfo
5+
*.bkp
6+
7+
# env files
8+
.env*
9+
!.env.local.example
10+
!.env.credentials
11+
12+
# next.js
13+
.next
14+
out
15+
16+
# cdk
17+
cdk.out
18+
.cdk.staging
19+
20+
# debug
21+
npm-debug.log*
22+
yarn-debug.log*
23+
.pnpm-debug.log*
24+
25+
# generated
26+
dist
27+
28+
# dev tools
29+
.kiro/settings/
30+
.playwright-cli/

.oxfmtrc.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "./node_modules/oxfmt/configuration_schema.json",
3+
"trailingComma": "all",
4+
"tabWidth": 2,
5+
"semi": true,
6+
"singleQuote": true,
7+
"printWidth": 120
8+
}

.prettierrc

Lines changed: 0 additions & 7 deletions
This file was deleted.

.serverless-full-stack-webapp-starter-kit/design/DESIGN_PRINCIPLES.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ As an aws-samples project:
1313
- Correctness is the top priority — users learn patterns from this code.
1414
- Reproducibility — following the README must produce a working deployment.
1515
- Readability — code should be understandable by developers new to serverless.
16-
- One-command deploy — `npx cdk deploy --all` must be the only deployment step.
16+
- One-command deploy — `pnpm exec cdk deploy --all` must be the only deployment step.
1717

1818
The litmus test for any PR: "After this merges, will a developer who copies the kit build their app on a correct understanding?"
1919

@@ -41,12 +41,14 @@ The litmus test for any PR: "After this merges, will a developer who copies the
4141

4242
| Choice | Rationale |
4343
|--------|-----------|
44-
| `prisma db push` over `prisma migrate` | Simpler default for starter-kit scope. Users can switch to `prisma migrate` when they need migration history. |
45-
| NAT Instance over NAT Gateway | ~$30/month savings. Acceptable trade-off for a starter kit. |
44+
| Aurora DSQL over Aurora Serverless v2 | No VPC required, true pay-per-request, IAM authentication. Eliminates NAT Instance cost and VPC complexity. |
45+
| Drizzle ORM over Prisma | Pure TypeScript (no `prisma generate`), `relations()` naturally fits DSQL's no-FK constraint, simpler monorepo sharing. |
46+
| Custom migration runner over `drizzle-kit push` | DSQL requires 1 DDL per transaction. The runner splits SQL on blank lines and validates DSQL compatibility before execution. |
4647
| Single Lambda for all async jobs | Reduces cold starts and simplifies deployment. `cmd` parameter selects the entry point. |
4748
| `proxy.ts` over Next.js middleware | Runs inside Lambda handler, avoiding cold-start CPU starvation from JWKS fetch in middleware. |
4849
| `output: 'standalone'` | Required for Lambda deployment via Docker image. |
4950
| Lambda Web Adapter | Enables response streaming with CloudFront + Lambda Function URL. |
51+
| oxlint + oxfmt over ESLint + Prettier | Faster linting and formatting. Type-aware linting via oxlint-tsgolint replaces `tsc --noEmit`. |
5052

5153
### Architecture Decision Records (ADR)
5254

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.0.3 Chrome/140.0.7339.249 Electron/38.7.0 Safari/537.36" version="29.0.3">
2+
<diagram name="Architecture" id="arch">
3+
<mxGraphModel dx="1018" dy="1149" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="1100" pageHeight="800" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="g1" value="Webapp" style="rounded=1;whiteSpace=wrap;fillColor=#E8F5E9;strokeColor=#388E3C;fontSize=16;fontStyle=1;verticalAlign=top;spacingTop=8;arcSize=8;" parent="1" vertex="1">
8+
<mxGeometry x="160" y="-30" width="420" height="310" as="geometry" />
9+
</mxCell>
10+
<mxCell id="g2" value="Authentication" style="rounded=1;whiteSpace=wrap;fillColor=#FFF3E0;strokeColor=#F57C00;fontSize=16;fontStyle=1;verticalAlign=top;spacingTop=8;arcSize=8;" parent="1" vertex="1">
11+
<mxGeometry x="590" y="-30" width="200" height="150" as="geometry" />
12+
</mxCell>
13+
<mxCell id="g3" value="Database" style="rounded=1;whiteSpace=wrap;fillColor=#FFF8E1;strokeColor=#FBC02D;fontSize=16;fontStyle=1;verticalAlign=top;spacingTop=8;arcSize=8;" parent="1" vertex="1">
14+
<mxGeometry x="590" y="130" width="200" height="150" as="geometry" />
15+
</mxCell>
16+
<mxCell id="g4" value="Asynchronous Job" style="rounded=1;whiteSpace=wrap;fillColor=#FCE4EC;strokeColor=#E91E63;fontSize=16;fontStyle=1;verticalAlign=top;spacingTop=8;arcSize=8;" parent="1" vertex="1">
17+
<mxGeometry x="160" y="290" width="420" height="160" as="geometry" />
18+
</mxCell>
19+
<mxCell id="g5" value="Scheduled Job" style="rounded=1;whiteSpace=wrap;fillColor=#F3E5F5;strokeColor=#9C27B0;fontSize=16;fontStyle=1;verticalAlign=top;spacingTop=8;arcSize=8;" parent="1" vertex="1">
20+
<mxGeometry x="590" y="290" width="200" height="160" as="geometry" />
21+
</mxCell>
22+
<mxCell id="e1" value="Send Requests" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;fontSize=13;labelBackgroundColor=default;spacing=2;" parent="1" source="users" target="cf" edge="1">
23+
<mxGeometry relative="1" as="geometry" />
24+
</mxCell>
25+
<mxCell id="e2" value="Lambda Function URL" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;fontSize=13;verticalAlign=bottom;labelBackgroundColor=none;spacing=2;" parent="1" source="cf" target="nextjs" edge="1">
26+
<mxGeometry relative="1" as="geometry" />
27+
</mxCell>
28+
<mxCell id="e5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;exitX=1;exitY=0.5;entryX=0;entryY=0.5;" parent="1" source="nextjs" target="dsql" edge="1">
29+
<mxGeometry relative="1" as="geometry" />
30+
</mxCell>
31+
<mxCell id="e6" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;dashed=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;fontSize=13;labelBackgroundColor=default;spacing=2;" parent="1" source="nextjs" target="jobhandler" edge="1">
32+
<mxGeometry relative="1" as="geometry" />
33+
</mxCell>
34+
<mxCell id="e7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;exitX=0;exitY=0.5;entryX=1;entryY=0.5;" parent="1" source="jobhandler" target="appsync" edge="1">
35+
<mxGeometry relative="1" as="geometry" />
36+
</mxCell>
37+
<mxCell id="e8" value="Real-time&#xa;Notification" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;dashed=1;exitX=0;exitY=0.5;fontSize=13;labelBackgroundColor=default;spacing=2;" parent="1" source="appsync" target="users" edge="1">
38+
<mxGeometry relative="1" as="geometry">
39+
<mxPoint x="50" y="260" as="targetPoint" />
40+
</mxGeometry>
41+
</mxCell>
42+
<mxCell id="e9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;dashed=1;exitX=0;exitY=0.5;entryX=1;entryY=0.5;" parent="1" source="eb" target="jobhandler" edge="1">
43+
<mxGeometry relative="1" as="geometry" />
44+
</mxCell>
45+
<mxCell id="users" value="Users" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=13;fontStyle=1;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.users;fillColor=#232F3D;" parent="1" vertex="1">
46+
<mxGeometry x="50" y="170" width="60" height="60" as="geometry" />
47+
</mxCell>
48+
<mxCell id="YBvlDhobisiv5zPTTUV7-2" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.308;entryY=1.025;entryDx=0;entryDy=0;entryPerimeter=0;edgeStyle=orthogonalEdgeStyle;" edge="1" parent="1" source="cf" target="gEdge">
49+
<mxGeometry relative="1" as="geometry" />
50+
</mxCell>
51+
<mxCell id="cf" value="CloudFront" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.cloudfront;fillColor=#8C4FFF;" parent="1" vertex="1">
52+
<mxGeometry x="230" y="170" width="60" height="60" as="geometry" />
53+
</mxCell>
54+
<mxCell id="nextjs" value="Next.js&#xa;Lambda Web Adapter" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.lambda;fillColor=#ED7100;" parent="1" vertex="1">
55+
<mxGeometry x="450" y="170" width="60" height="60" as="geometry" />
56+
</mxCell>
57+
<mxCell id="cognito" value="&lt;span&gt;Cognito&lt;/span&gt;&lt;br&gt;User Pool" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.cognito;fillColor=#DD344C;" parent="1" vertex="1">
58+
<mxGeometry x="660" y="10" width="60" height="60" as="geometry" />
59+
</mxCell>
60+
<mxCell id="dsql" value="Aurora DSQL" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.aurora;fillColor=#C925D1;" parent="1" vertex="1">
61+
<mxGeometry x="660" y="170" width="60" height="60" as="geometry" />
62+
</mxCell>
63+
<mxCell id="appsync" value="AppSync Events" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.appsync;fillColor=#E7157B;" parent="1" vertex="1">
64+
<mxGeometry x="230" y="330" width="60" height="60" as="geometry" />
65+
</mxCell>
66+
<mxCell id="jobhandler" value="Job Handler" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.lambda;fillColor=#ED7100;" parent="1" vertex="1">
67+
<mxGeometry x="450" y="330" width="60" height="60" as="geometry" />
68+
</mxCell>
69+
<mxCell id="eb" value="EventBridge&#xa;Scheduler" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=14;fontStyle=1;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.eventbridge;fillColor=#E7157B;" parent="1" vertex="1">
70+
<mxGeometry x="660" y="330" width="60" height="60" as="geometry" />
71+
</mxCell>
72+
<mxCell id="YBvlDhobisiv5zPTTUV7-1" value="" style="group" vertex="1" connectable="0" parent="1">
73+
<mxGeometry x="184" y="30" width="250" height="80" as="geometry" />
74+
</mxCell>
75+
<mxCell id="gEdge" value="" style="rounded=1;whiteSpace=wrap;fillColor=none;strokeColor=#ED7100;fontSize=10;arcSize=12;" vertex="1" parent="YBvlDhobisiv5zPTTUV7-1">
76+
<mxGeometry x="-1" width="250" height="80" as="geometry" />
77+
</mxCell>
78+
<mxCell id="edge" value="&lt;b&gt;Lambda@Edge&lt;br&gt;&lt;/b&gt;&amp;nbsp; SigV4 Request Signer" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;strokeColor=none;dashed=0;verticalLabelPosition=middle;labelPosition=right;verticalAlign=middle;align=left;html=1;fontSize=14;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.lambda;fillColor=#ED7100;spacing=6;" parent="YBvlDhobisiv5zPTTUV7-1" vertex="1">
79+
<mxGeometry x="10" y="7" width="28" height="28" as="geometry" />
80+
</mxCell>
81+
<mxCell id="cff" value="&lt;b&gt;CloudFront Functions&lt;br&gt;&lt;/b&gt;&amp;nbsp; Next.js Cache Header Editor" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;strokeColor=none;dashed=0;verticalLabelPosition=middle;labelPosition=right;verticalAlign=middle;align=left;html=1;fontSize=14;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.lambda;fillColor=#ED7100;spacing=6;" vertex="1" parent="YBvlDhobisiv5zPTTUV7-1">
82+
<mxGeometry x="10" y="45" width="28" height="28" as="geometry" />
83+
</mxCell>
84+
</root>
85+
</mxGraphModel>
86+
</diagram>
87+
</mxfile>
100 KB
Loading
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# v3 Migration Guide: pnpm Workspaces + DSQL + Drizzle
2+
3+
This guide covers the major changes in v3 for users migrating from v2.
4+
5+
## Breaking changes
6+
7+
### 1. Package manager: npm → pnpm workspaces
8+
9+
The project is now a pnpm monorepo. All `npm` commands should be replaced with `pnpm`.
10+
11+
- `npm ci``pnpm install`
12+
- `npm run build``pnpm run build`
13+
- `package-lock.json``pnpm-lock.yaml`
14+
15+
### 2. ORM: Prisma → Drizzle
16+
17+
Prisma has been replaced with Drizzle ORM for DSQL compatibility.
18+
19+
Key differences:
20+
- No `prisma generate` step — Drizzle is pure TypeScript
21+
- Schema defined in `packages/db/src/schema.ts` using Drizzle's `pgTable()` API
22+
- Relations use `relations()` (query builder only, no SQL-level FK)
23+
- Zod schemas are hand-written, not generated from the ORM
24+
25+
Migration steps for custom code:
26+
1. Replace `@prisma/client` imports with `@repo/db/client` and `@repo/db/schema`
27+
2. Replace `prisma.model.findMany()` with `db.query.model.findMany()` or `db.select().from(table)`
28+
3. Replace `prisma.model.create()` with `db.insert(table).values()`
29+
4. Replace `prisma.model.update()` with `db.update(table).set().where()`
30+
5. Replace `prisma.model.delete()` with `db.delete(table).where()`
31+
32+
### 3. Database: Aurora Serverless v2 → Aurora DSQL
33+
34+
Aurora Serverless v2 (VPC-bound) has been replaced with Aurora DSQL (VPC-free).
35+
36+
Key differences:
37+
- No VPC, NAT Instance, or Bastion Host required
38+
- IAM authentication instead of username/password
39+
- DSQL constraints: no SERIAL, no FK, no JSON/JSONB, 1 DDL per transaction
40+
- `CREATE INDEX` must use `ASYNC` keyword
41+
42+
### 4. VPC removal
43+
44+
The entire VPC stack has been removed. Lambda functions connect to DSQL over the public internet with IAM authentication.
45+
46+
### 5. Project structure
47+
48+
```
49+
# v2
50+
webapp/ → apps/webapp/
51+
cdk/ → apps/cdk/
52+
apps/async-job/ (new, extracted from webapp/src/jobs/)
53+
packages/db/ (new, Drizzle schema + migration runner)
54+
packages/shared-types/ (new, job payload types)
55+
```
56+
57+
### 6. Linting: ESLint + Prettier → oxlint + oxfmt
58+
59+
ESLint and Prettier have been replaced with oxlint and oxfmt for faster linting.
60+
61+
### 7. Docker builds in pnpm monorepo (strict mode, no shamefully-hoist)
62+
63+
Key constraints when building Docker images from a pnpm workspace without `shamefully-hoist`:
64+
65+
- **`pnpm install --filter` does not hoist transitive dependencies of workspace packages.** If `apps/async-job` depends on `@repo/db`, and `@repo/db` depends on `pg`, esbuild inside Docker cannot resolve `pg` from `apps/async-job/node_modules`. Use `pnpm install --frozen-lockfile` (no `--filter`) in Dockerfiles.
66+
- **CDK `DockerImageCode.fromImageAsset` does not read `.dockerignore` by default.** Set `ignoreMode: IgnoreMode.DOCKER` on every Docker asset whose build context is the monorepo root. Without this, `cdk.out` is recursively copied into itself, causing `ENAMETOOLONG`.
67+
- **esbuild `--format=esm` output requires `.mjs` extension for Lambda.** The Lambda Node.js runtime loads handlers as CommonJS unless the file has `.mjs` extension or a `package.json` with `"type": "module"` exists in `/var/task`.
68+
- **`@aws/*``@aws-sdk/*`.** `--external:@aws-sdk/*` does not exclude `@aws/aurora-dsql-node-postgres-connector`. Lambda runtime only provides `@aws-sdk/*`; other `@aws/*` packages must be bundled by esbuild.

0 commit comments

Comments
 (0)