From 21b4ea8302de76cd19b7c5ccc7e00f5994aa190e Mon Sep 17 00:00:00 2001 From: Xiro The Dev Date: Sat, 5 Sep 2026 14:59:13 +0700 Subject: [PATCH 1/3] =?UTF-8?q?ci:=20CD=20rehearsal=20workflow=20=E2=80=94?= =?UTF-8?q?=20build=20all=20CD=20images=20+=20CDK=20app=20checks=20offline?= =?UTF-8?q?,=20on=20v*=20tags=20and=20dispatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd-local.yml | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/cd-local.yml diff --git a/.github/workflows/cd-local.yml b/.github/workflows/cd-local.yml new file mode 100644 index 0000000..4f07ed2 --- /dev/null +++ b/.github/workflows/cd-local.yml @@ -0,0 +1,65 @@ +name: CD Rehearsal (LocalStack) + +# Exercises everything the real CD (cd.yml) needs, without an AWS account. +# Not a live `cdk deploy` against LocalStack: the bootstrap-ECR lookup at +# synth time refuses endpoint overrides, and ECR/ECS push + blue/green are +# Pro-only services. S3-level simulator coverage lives in ci.yml's +# storage-smoke job. What actually breaks real deploys — Dockerfiles, the +# CDK app, the BucketDeployment asset — is fully covered here. + +on: + push: + tags: ['v*'] + workflow_dispatch: + +concurrency: + group: cd-rehearsal-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + images: + name: Build (${{ matrix.app }}) + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + max-parallel: 2 + matrix: + include: + - app: api + dockerfile: apps/api/Dockerfile + - app: web + dockerfile: apps/web/Dockerfile + - app: api-go + dockerfile: apps/api-go/Dockerfile + - app: api-axum + dockerfile: apps/api-axum/Dockerfile + - app: api-elysia + dockerfile: apps/api-elysia/Dockerfile + steps: + - uses: actions/checkout@v7 + - uses: docker/setup-buildx-action@v4 + - uses: docker/build-push-action@v7 + with: + context: . + file: ${{ matrix.dockerfile }} + push: false + cache-from: type=gha,scope=rehearsal-${{ matrix.app }} + cache-to: type=gha,mode=max,scope=rehearsal-${{ matrix.app }} + + cdk-app: + name: CDK app + static assets + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + - uses: ./.github/actions/setup-bun-node + - name: Build web-vue static bundle (BucketDeployment asset) + run: bun run --cwd apps/web-vue build + - name: Typecheck and stack tests (offline CDK Template assertions) + run: | + bun run --cwd infra typecheck + bun run --cwd infra test From adbc3c3fdb07cf4cae43a2c7c8aabce4407d2420 Mon Sep 17 00:00:00 2001 From: Xiro The Dev Date: Sat, 5 Sep 2026 15:03:33 +0700 Subject: [PATCH 2/3] chore: ignore infra/cdk.context.json --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3410530..5f46876 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ apps/api-go/server apps/api-go/api-go *.exe infra/cdk.out + +# CDK context cache (regenerated per environment) +infra/cdk.context.json From 42246a653941ed6cde4645e8180e57ed7847a8f4 Mon Sep 17 00:00:00 2001 From: Xiro The Dev Date: Sat, 5 Sep 2026 15:39:48 +0700 Subject: [PATCH 3/3] fix(docker): copy all workspace manifests and pin bun 1.3.14 so image builds satisfy the frozen lockfile --- apps/api-elysia/Dockerfile | 6 +++++- apps/api/Dockerfile | 16 +++++++++++++--- apps/web/Dockerfile | 9 +++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/api-elysia/Dockerfile b/apps/api-elysia/Dockerfile index dd207e6..26b9140 100644 --- a/apps/api-elysia/Dockerfile +++ b/apps/api-elysia/Dockerfile @@ -3,13 +3,17 @@ # ponytail: single-stage install + run src with bun (bun needs no build step). # api's layered cache stages only matter for prod deploys; this Mirror boots from src. -FROM oven/bun:1 AS base +FROM oven/bun:1.3.14-alpine AS base WORKDIR /app COPY package.json bun.lock ./ COPY apps/api-elysia/package.json ./apps/api-elysia/ COPY apps/web/package.json ./apps/web/ COPY apps/api/package.json ./apps/api/ +COPY apps/api-axum/package.json ./apps/api-axum/ +COPY apps/api-effect/package.json ./apps/api-effect/ +COPY apps/web-vue/package.json ./apps/web-vue/ +COPY infra/package.json ./infra/ RUN --mount=type=cache,target=/root/.bun/install/cache \ bun install --frozen-lockfile --ignore-scripts diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index e0d7795..6e4236e 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -8,6 +8,11 @@ FROM base AS deps COPY package.json bun.lock ./ COPY apps/web/package.json ./apps/web/ COPY apps/api/package.json ./apps/api/ +COPY apps/api-axum/package.json ./apps/api-axum/ +COPY apps/api-effect/package.json ./apps/api-effect/ +COPY apps/api-elysia/package.json ./apps/api-elysia/ +COPY apps/web-vue/package.json ./apps/web-vue/ +COPY infra/package.json ./infra/ # Copy Prisma schema and config for postinstall script COPY apps/api/prisma.config.ts ./apps/api/ COPY apps/api/prisma ./apps/api/prisma @@ -16,7 +21,7 @@ COPY apps/api/tsconfig.json ./apps/api/ ENV CI=true # Cache mount: bun's download store persists even when the layer invalidates RUN --mount=type=cache,target=/root/.bun/install/cache \ - bun install --frozen-lockfile --linker isolated + bun install --frozen-lockfile --ignore-scripts --linker isolated # Prisma stage — client regenerates only when schema or lockfile changes FROM deps AS prisma @@ -48,6 +53,11 @@ RUN addgroup --system --gid 1001 nodejs && \ COPY package.json bun.lock ./ COPY apps/web/package.json ./apps/web/ COPY apps/api/package.json ./apps/api/ +COPY apps/api-axum/package.json ./apps/api-axum/ +COPY apps/api-effect/package.json ./apps/api-effect/ +COPY apps/api-elysia/package.json ./apps/api-elysia/ +COPY apps/web-vue/package.json ./apps/web-vue/ +COPY infra/package.json ./infra/ ENV CI=true RUN --mount=type=cache,target=/root/.bun/install/cache \ @@ -58,8 +68,8 @@ COPY --from=builder --chown=nestjs:nodejs /app/apps/api/src ./apps/api/src COPY --from=builder --chown=nestjs:nodejs /app/apps/api/prisma ./apps/api/prisma COPY --from=builder --chown=nestjs:nodejs /app/node_modules ./node_modules COPY --from=builder --chown=nestjs:nodejs /app/apps/api/node_modules ./apps/api/node_modules -COPY --from=builder /app/package.json ./package.json -COPY --from=builder /app/apps/api/package.json ./apps/api/package.json +COPY --from=builder --chown=nestjs:nodejs /app/package.json ./package.json +COPY --from=builder --chown=nestjs:nodejs /app/apps/api/package.json ./apps/api/package.json # Runtime tsconfig: aliases must resolve into dist so bun loads ONE copy of each # class. Mapping @/* to ./src/* instead makes Nest register a class from dist diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 459ab14..c4c2c73 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -8,11 +8,16 @@ FROM base AS deps COPY package.json bun.lock ./ COPY apps/web/package.json ./apps/web/ COPY apps/api/package.json ./apps/api/ +COPY apps/api-axum/package.json ./apps/api-axum/ +COPY apps/api-effect/package.json ./apps/api-effect/ +COPY apps/api-elysia/package.json ./apps/api-elysia/ +COPY apps/web-vue/package.json ./apps/web-vue/ +COPY infra/package.json ./infra/ # Copy Prisma schema and config for the API workspace postinstall script COPY apps/api/prisma.config.ts ./apps/api/ COPY apps/api/prisma ./apps/api/prisma COPY apps/api/tsconfig.json ./apps/api/ -RUN bun install --frozen-lockfile --linker isolated +RUN bun install --frozen-lockfile --ignore-scripts --linker isolated # Builder stage FROM base AS builder @@ -38,7 +43,7 @@ RUN addgroup --system --gid 1001 nodejs && \ adduser --system --uid 1001 nextjs # Copy necessary files -COPY --from=builder /app/apps/web/public ./apps/web/public +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static