Skip to content

v3.0.0

Choose a tag to compare

@github-actions github-actions released this 23 Jul 08:30
7ffcd88

πŸ‡―πŸ‡΅ ζ—₯本θͺžη‰ˆ: .starter-kit/docs/v3.0.0/release-notes.ja.md (available once #273 is merged)

3.0.0 (2026-07-23)

v3.0.0 β€” Aurora DSQL, pnpm workspaces monorepo, oxlint/oxfmt, deploy-time image build, CloudFront flat-rate

You copy this kit and grow it into your own app. These release notes are written for two audiences: (a) developers starting fresh from v3, and (b) owners of an app previously copied from v2 who want to decide which changes to selectively adopt without a full v3 migration.

How to read this:

  • Starting fresh from v3? Read Β§1 Highlights, follow the README Getting started, and then complete the post-deploy CloudFront Free plan enrollment described in Β§2.3. Β§2.1, Β§2.2, and Β§3 mainly matter to v2 owners.
  • v2 owner deciding what to adopt? Read Β§2 for the incompatible changes you'd take on with a full migration, and Β§3 for improvements you can selectively port to a v2 tree.
  • Section-level applicability tags ("Applies to") below tell you when a change concerns you.

1. Highlights

(All numbers here are per-component prices for the sample-app workload β€” see the README Cost table for the total monthly estimate ($2.42) using v3 defaults.)

  • Aurora DSQL + Drizzle ORM replace Aurora Serverless v2 + Prisma. No VPC / NAT / bastion; IAM auth over the public internet; pay per RPU (Request Processing Unit β€” DSQL's per-transaction pricing metric, see the DSQL pricing page) with no minimum, so idle traffic costs zero. See ADR-001. Trade-off: DSQL is a distributed SQL engine with stricter DDL semantics (no SERIAL / FK / TRUNCATE, one DDL per transaction, restricted ALTER TABLE), which shape the ORM patterns you can use.
  • pnpm workspaces monorepo (apps/webapp, apps/async-job, apps/cdk, packages/db, packages/event-utils, packages/shared-types, plus the later-added apps/db-migrator) replaces the two-package webapp/ + cdk/ layout. Workspace-local packages (e.g. @repo/db, @repo/shared-types) give you an in-repo type-sharing surface without publishing. See ADR-002.
  • oxlint + oxfmt replace ESLint + Prettier. Rust-based, fast enough to run on every file save; type-aware linting via oxlint-tsgolint obsoletes a separate tsc --noEmit pass. See ADR-003.
  • Deploy-time container image build via @cdklabs/deploy-time-build for the webapp and async-job Lambda images. No local Docker required at deploy time; images are built in CodeBuild (ARM64) from CDK synth. The db-migrator is deliberately a zip-packaged NodejsFunction (bundled with esbuild, no Docker or CodeBuild involved) so that migrations re-run reliably on content changes and container cold-init races cannot break the deploy-time migration trigger (#229 / #231). See ADR-006.
  • CloudFront flat-rate pricing plan support. Managed cache policies (CACHING_DISABLED + CACHING_OPTIMIZED) + a KnownBadInputs WAF Web ACL in us-east-1. Structurally eliminates a class of bug where React Server Component (RSC, text/x-component) payloads could poison the HTML cache of the same path (superseded #176). Enroll in the Free plan post-deploy to bundle CDN + WAF + DDoS protection + logs at $0 for 1M requests / 100 GB per month; until you enroll, the required WAF Web ACL is billed at standard AWS WAF prices (~$5/month + $1/month per rule). See ADR-007 and Β§2.3 below.

2. Breaking changes

Each item below documents an incompatible change with an "Applies to" tag so you can tell whether it concerns you.

2.1 Repository layout, database, and toolchain overhaul β€” c986401

Applies to: v2 owners doing a full substrate migration. If you're staying on v2, this whole section does not apply.

The v3 kit is a pnpm workspaces monorepo (apps/*, packages/*) using Aurora DSQL + Drizzle ORM + oxlint/oxfmt. Aurora Serverless v2, Prisma, ESLint, Prettier, the webapp/ + cdk/ two-package layout, compose.yaml, and package-lock.json are removed. The webapp and async-job continue to run on Lambda behind CloudFront (webapp via Lambda Web Adapter with response streaming), and Cognito, AppSync Events, and EventBridge remain as before.

Impact for v2-derived apps: this is a whole-substrate migration. There is no partial-adoption path for the substrate itself; individual improvements built on top of it are documented in Β§3.

Migration guide: .starter-kit/docs/v3.0.0/migration-prompt.md β€” a phased meta-prompt intended to be read by an AI coding agent that migrates your v2 codebase. It covers the copy-vs-transform file inventory, schema.prisma-driven schema conversion, staged build verification, and VPC-attached Lambda networking (Hyperplane ENI) cleanup after DSQL cutover.

2.2 Migration files standardized on .sql + .mjs; runner hardened against silent re-run β€” 56f7be4

Applies to: anyone taking the DSQL substrate (i.e. only after adopting Β§2.1). If you're staying on Aurora Serverless v2 + Prisma, this section does not apply.

Only .sql and .mjs files under packages/db/migrations/ are executed. .ts migration files are silently ignored (not rejected β€” the runner filters them). The full file name including extension is recorded in the _migrations table, so renaming 0002_foo.ts β†’ 0002_foo.mjs on an already-migrated database causes the runner to treat it as a new file and re-execute the migration. The dsql-compat validator also now rejects ADD COLUMN with inline constraints (DEFAULT / NOT NULL / CHECK / UNIQUE / PRIMARY KEY) because DSQL requires table recreation for those.

The migrator is a zip-packaged NodejsFunction whose bundle includes the migrations/ directory, so any content change under migrations/ flows into CDK's standard asset hash, publishes a new Lambda version, and re-runs the runner on the next deploy (#231 β€” this replaced an earlier custom directory-hash mechanism and structurally avoids container cold-init races breaking the deploy-time trigger).

If you have .ts migrations, either (a) rename each .ts to .mjs, port the code (see the JSDoc-typed sample migrations under packages/db/migrations/), and update _migrations.name in the database to match β€” or (b) make each migration idempotent and rename without the DB update.

Migration guide: .starter-kit/docs/v3.0.0/adr-005-migration-file-format.md.

2.3 CloudFront: managed cache policies + us-east-1 WAF Web ACL (flat-rate-plan compatible) β€” 9bfa073

Applies to: new v3 users (post-deploy Free-plan enrollment is required) and v2 owners considering selective adoption. See Β§3.1 for the port procedure if you're on v2. Skippable only if you deliberately choose not to enroll in the Free plan and remove the Web ACL.

The custom SharedCachePolicy (all query strings, RSC-friendly header allow-list, all cookies, TTL 0) is replaced by AWS-managed CACHING_DISABLED on the default behavior and CACHING_OPTIMIZED on /_next/static/*. A WAF Web ACL (scope CLOUDFRONT, region us-east-1) is added carrying only the KnownBadInputs managed rule (rate-based, AmazonIpReputationList, and CommonRuleSet are intentionally omitted; see the inline comments and ADR-007 for reasons). The webAclId is passed to the main-region stack via CDK crossRegionReferences: true.

This structurally eliminates a class of bug where RSC payloads (text/x-component) could poison the HTML cache of the same path β€” since the default behavior no longer caches at all β€” and unblocks enrollment in CloudFront flat-rate pricing plans (Free / Pro / Business / Premium) which require a WAF Web ACL and forbid custom cache policies.

Post-deploy manual step: open your distribution in the CloudFront console and choose Manage subscription β†’ Free plan. Until you do, the WAF Web ACL is billed at standard AWS WAF prices (~$5/month + $1/month per rule). To opt out of WAF entirely, remove the Web ACL in apps/cdk/lib/us-east-1-stack.ts and drop webAclId from apps/cdk/bin/cdk.ts (procedure in README).

Migration guide: README Β§4 β€œEnroll in the CloudFront Free plan” and .starter-kit/docs/v3.0.0/adr-007-cloudfront-flat-rate.md.

3. Selective adoption guide

If you already copied v2 and don't want to migrate the whole substrate, the changes below can be adopted individually. Cherry-picking is not literal β€” v2/v3 paths differ (webapp/ β†’ apps/webapp/, cdk/ β†’ apps/cdk/), so a git cherry-pick will conflict. Treat each entry as "port the diff to the same file in your v2 tree by hand".

Each entry uses the format: v3 source files β†’ v2 destination(s) / prerequisites / notes. Subject lines in this section are normalized English release-note labels; the linked commit shows the verbatim commit subject (some are in Japanese, e.g. #174/#182/#184/#185/#186).

Everything else in v3 that isn't listed here (workspace layout, DSQL migration runner, drizzle-kit generate/check pipeline, DSQL compatibility validator, pre-commit hooks via simple-git-hooks, ContainerImageBuild container images, DSQL cluster CLI in TypeScript, Node 24 base images, pnpm 10.34.4, and @repo/event-utils) is inseparable from the v3 substrate and requires the full migration in Β§2.1.

3.1 Selectively adoptable improvements
  • e62704a β€” refactor(webapp): split auth session and adopt optimistic proxy check. Non-breaking API change. Splits getSession() into getAuthSession (cached), tryGetAuthSession (never throws), and getSessionWithUser. proxy.ts becomes an optimistic Cookie-presence check (Amplify LastAuthUser); token verification is deferred to the data-access layer. Adds Vitest and 18 unit tests.
    • v3 source β†’ v2 target: apps/webapp/src/lib/auth.ts β†’ webapp/src/lib/auth.ts; apps/webapp/src/proxy.ts β†’ webapp/src/middleware.ts (if your v2 tree pre-dates Next.js 16, keep the middleware.ts name and adjust its matcher); update callers in app/(root)/page.tsx, auth-callback/page.tsx, app/api/cognito-token/route.ts.
    • Prerequisites: none. Skip vitest.config.ts if you don't want tests.
  • 458414a β€” feat(webapp): add withAuth() API Route authentication helper and migrate /api/cognito-token. Non-breaking.
    • v3 source β†’ v2 target: apps/webapp/src/lib/api/with-auth.ts β†’ webapp/src/lib/api/with-auth.ts; adopt in your existing Route Handlers under app/api/**/route.ts.
    • Prerequisites: e62704a (uses tryGetAuthSession). Handlers returning non-JSON responses (bearer, binary) should keep tryGetAuthSession directly.
  • a3ee713 β€” fix(cdk): RETAIN Lambda@Edge versions to avoid DELETE_FAILED on redeploy. Three-line change.
    • v3 source β†’ v2 target: apps/cdk/lib/constructs/cf-lambda-furl-service/edge-function.ts β†’ cdk/lib/constructs/cf-lambda-furl-service/edge-function.ts (set currentVersionOptions.removalPolicy = RemovalPolicy.RETAIN).
    • Notes: retained Lambda versions accumulate over deploys and must be pruned manually via the Lambda console/CLI only after confirming the CloudFront replica is removed.
  • b18d6c6 β€” feat(cdk): expose removalPolicy / deletionProtection on the Auth construct. Non-breaking; changes the default UserPool RemovalPolicy from DESTROY to RETAIN_ON_UPDATE_OR_DELETE.
    • v3 source β†’ v2 target: apps/cdk/lib/constructs/auth/index.ts β†’ cdk/lib/constructs/auth/index.ts.
    • Notes: if your CI tears environments down between runs, pass RemovalPolicy.DESTROY explicitly at instantiation.
  • 3ceeaf9 β€” fix(webapp): set httpOnly / secure / sameSite on Amplify server auth cookies.
    • v3 source β†’ v2 target: apps/webapp/src/lib/amplifyServerUtils.ts β†’ webapp/src/lib/amplifyServerUtils.ts (add the runtimeOptions.cookies block).
    • Notes: if you serve the app over plain HTTP (e.g. containerized non-HTTPS test rig with a custom domain), secure: true will suppress the Cookie β€” validate against your topology.
  • 5b6cf43 β€” fix(webapp): add /api/health readiness route and upgrade Lambda Web Adapter to 1.0.1.
    • v3 source β†’ v2 target: apps/webapp/src/app/api/health/route.ts β†’ webapp/src/app/api/health/route.ts (unauthenticated GET, returns 200, no DB / auth probes); Dockerfile COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.0.1. The DSQL grant partition fix (Stack.formatArn()) applies only if you use DSQL in aws-cn / aws-us-gov.
    • Prerequisites: your Dockerfile sets AWS_LWA_READINESS_CHECK_PATH=/api/health, or you use LWA at all.
  • a0d90c8 β€” chore: pin minimumReleaseAge: 4320 (72h) in pnpm-workspace.yaml. Supply-chain hardening.
    • v3 source β†’ v2 target: applies only if your v2 tree already uses pnpm-workspace.yaml. If you're still on npm, this doesn't port literally β€” the closest npm equivalent is to pin exact versions.
    • Notes: if you need a hotfix that was released within 72h, use pnpm add pkg@x.y.z --ignore-workspace as a temporary escape.
  • 7c7926b / 530c512 / 568dba0 β€” docs: v3.0.0 design doc, ADRs, and migration prompt (initial + rewrite + staged verification steps). Documentation, no runtime impact.
    • v3 source β†’ v2 target: copy .starter-kit/docs/v3.0.0/* into your app if you want the design record. Note the meta-prompt targets v2 β†’ v3 migration; it's only useful if you're planning that migration.
3.2 Selectively adoptable release-blocker fixes (PR #226)

Consolidated fix PR #226 (A1–A7 from the review-triage report). Squashed into dev/v3 as a single commit (per D6 branch policy) β€” refer to the PR to see each individual commit and its diff. The individual patches vary in whether they can be ported to v2.

ID v3 commit Type Summary v2 portable?
A1 9f40813 fix(cdk) Send discriminated-union payload for the scheduled example EventBridge job (previous sample job's payload failed Zod validation at receipt). Partially β€” v2 does not use @repo/shared-types; port the payload shape and Zod schema by hand.
A2 0400216 fix(cdk) Use RFC 5737 documentation IP (192.0.2.1) for the Cognito parent A record instead of 8.8.8.8 (aws-samples style-guide compliance). Yes β€” one-line change.
A3 0ed3e7f fix(cdk) Use Cognito sub (not username) in AppSync subscribe auth and enforce a trailing / delimiter on startsWith prefix checks (avoids prefix collision). Yes if your v2 tree uses the same AppSync Events authorizer pattern β€” port the resolver diff.
A4 b2220ea chore(ci) Remove .github/workflows/update_snapshot.yml (snapshot-regeneration workflow driven by issue_comment was a policy hole for write-token code execution; snapshot changes now flow through the normal PR flow). Yes if your v2 tree has an equivalent workflow β€” delete it.
A5 a19c02c fix(event-utils) sendEvent() now throws on non-2xx AppSync responses (res.ok check) instead of silently swallowing failures β€” protects the documented E2E delivery guarantee. Port the res.ok check to your v2 sendEvent implementation (paths differ).
A6 d9f6c42 fix(cdk) prefix-generator.js custom resource logs only an allow-listed subset of fields β€” avoids leaking the presigned ResponseURL (secret) to CloudWatch. Yes if your v2 tree uses the same custom resource β€” port the logSafeEvent helper.
A7 6d192f3 docs AGENTS.md: correct description of proxy.ts (Next.js 16 file convention that renames middleware.ts; runs inside the Lambda handler, not as a separate Edge worker). v2 uses middleware.ts β€” this doc correction is v3-specific.

Note that A1–A7 do not appear as individual commits on main after v3 ships because #226 squash-merged them into a single commit on dev/v3 (per D6). PR #226 is the referenceable anchor for the full diff.

4. Deprecations and removed features

Applies to: new v3 users and v2 owners doing a full migration. If you already copied v2 and stay on v2, this release does not change or break your existing app β€” the removals below apply only to the v3 template / a full v3 migration. There is no forced-migration schedule.

Removed Replacement / rationale
Aurora Serverless v2 + Prisma Aurora DSQL + Drizzle ORM. See Β§2.1 and ADR-001.
VPC / private subnet / NAT / bastion DSQL uses IAM auth over the public internet β€” no VPC-scoped compute required.
ESLint + Prettier oxlint + oxfmt. See Β§1 highlights and ADR-003.
compose.yaml (local dev) Aurora DSQL provides a real cluster; no local Postgres emulation needed. Use pnpm --filter @repo/db run cluster create.
scripts/dsql.sh pnpm --filter @repo/db run cluster [create|delete|status] [--region REGION] (TypeScript, in packages/db/src/cluster-cli.ts).
npm / package-lock.json pnpm 10.34.4 + pnpm-lock.yaml. Root packageManager and engines.pnpm are declared.
Custom CloudFront SharedCachePolicy Managed CACHING_DISABLED + CACHING_OPTIMIZED. See Β§2.3 and ADR-007.
webapp/prisma/, webapp/src/lib/prisma.ts, webapp/src/jobs/* Moved to packages/db/ (schema, migrations, client) and apps/async-job/ (handlers).
Root scripts (pnpm run dev etc., 13 aliases) Removed. Use per-workspace commands (cd apps/webapp && pnpm run dev) or pnpm -r run <task> for all workspaces.
update_snapshot.yml Removed (A4). Snapshot changes go through the normal PR flow.

5. Known constraints

Each constraint is tagged with its applicability so you can tell whether it affects you based on how much of v3 you adopt.

  • DSQL constraints (Applies to: full v3 substrate β€” anyone on Aurora DSQL) β€” no SERIAL / SEQUENCE (use UUID), no FOREIGN KEY (use Drizzle relations() for query-time joins), no TRUNCATE (use DELETE FROM), CREATE INDEX must use ASYNC, one DDL per transaction, restricted ALTER TABLE (only ADD COLUMN without constraints, RENAME, SET SCHEMA, OWNER TO, IDENTITY). Full list in AGENTS.md and ADR-001.
  • RETAIN_ON_UPDATE_OR_DELETE defaults (Applies to: full v3 substrate; DSQL cluster and Auth construct Β§3.1 also when adopted individually) β€” the DSQL cluster and the Cognito UserPool are retained on cdk destroy. Delete them manually if you no longer need them. For automated tear-down (CI), pass RemovalPolicy.DESTROY explicitly on both constructs.
  • Lambda@Edge versions accumulate (Applies to: anyone adopting Β§3.1 a3ee713 or the full v3 substrate) β€” CloudFront replica removal is asynchronous, so v3 keeps old Lambda@Edge versions instead of failing the deploy. Prune manually via the Lambda console / CLI only after confirming no CloudFront distribution still references the version.
  • CloudFront Free plan enrollment is manual (Applies to: new v3 users and anyone adopting Β§2.3 CloudFront changes) β€” CDK cannot enroll a distribution in a flat-rate plan. Enroll from the console after the first deploy; until then, the Web ACL is billed at standard WAF prices.
  • DSQL admin role in v3 (Applies to: full v3 substrate β€” anyone on Aurora DSQL) β€” the webapp and async-job connect with DbConnectAdmin (see ADR-004). Production hardening (creating and granting a DML-only application role) is documented as future work.
  • Deploy-time image build has no local Docker cache (Applies to: full v3 substrate) β€” every image content change triggers a CodeBuild ARM64 job. Trade-off documented in ADR-006.