# syntax=docker/dockerfile:1

# One image, two roles: the dashboard runs `next start`, the worker runs
# `bun worker/index.ts`. They share the audit binary, the schema and the queue,
# so building them apart would only invite the two to drift.

# ---------------------------------------------------------------------------
# 1. The audit binary.
#
# Downloaded from a tagged release rather than compiled: a released tarball is
# the same bytes for everyone, where a build from source is a Rust toolchain, a
# crate index and three minutes of compilation standing between a deploy and
# production. The binaries are statically linked against musl, so the target
# base image does not matter and no runtime library has to agree with them.
#
# Pinned to a version, and verified: the release ships SHA256SUMS, and a
# download nobody checked is a supply chain nobody controls.
# ---------------------------------------------------------------------------
FROM debian:bookworm-slim AS audit-builder

# Bump to take a newer audit binary:
#   docker build --build-arg HSC_VERSION=v0.2.0 .
ARG HSC_VERSION=v0.1.0
# Set by buildx; the fallback keeps a plain `docker build` working.
ARG TARGETARCH=amd64

RUN apt-get update \
  && apt-get install -y --no-install-recommends curl ca-certificates \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /dl
RUN set -eu; \
  case "$TARGETARCH" in \
    amd64) triple=x86_64-unknown-linux-musl ;; \
    arm64) triple=aarch64-unknown-linux-musl ;; \
    *) echo "no audit binary is published for $TARGETARCH" >&2; exit 1 ;; \
  esac; \
  base="https://github.com/bastienallain/nextjs-seo-prerender-cli/releases/download/${HSC_VERSION}"; \
  asset="nextjs-seo-prerender-${HSC_VERSION}-${triple}.tar.gz"; \
  curl -fsSL -o "$asset" "${base}/${asset}"; \
  curl -fsSL -o SHA256SUMS "${base}/SHA256SUMS"; \
  grep " ${asset}\$" SHA256SUMS | sha256sum -c -; \
  tar -xzf "$asset"; \
  install -D -m 0755 nextjs-seo-prerender /out/nextjs-seo-prerender

# ---------------------------------------------------------------------------
# 2. The Next build.
# ---------------------------------------------------------------------------
FROM oven/bun:1 AS builder
WORKDIR /app

COPY package.json bun.lock ./
RUN bun install --frozen-lockfile

COPY . .
# Nothing secret is needed to build: every value is read at request time, and
# the only NEXT_PUBLIC_ one is the Turnstile site key, which is public by
# definition and reaches the browser through a server component's props.
ENV NEXT_TELEMETRY_DISABLED=1
RUN bun run build

# Drop the dev dependencies once the build no longer needs them. This is why
# next.config.ts does not use `output: standalone`: the worker is not part of
# the Next build and needs real modules for drizzle and pg, so one pruned
# node_modules serving both roles is smaller than a traced bundle plus a second
# copy — and it cannot be missing something Next's tracer failed to see.
#
# Pruning is also why the worker applies the migrations with `db/migrate.ts`
# rather than drizzle-kit, which does not survive this line.
RUN rm -rf node_modules && bun install --frozen-lockfile --production

# ---------------------------------------------------------------------------
# 3. The runtime.
#
# The audit binary is statically linked against musl, so it carries no opinion
# about this image's libc and none of the usual builder/runtime pairing applies.
# ca-certificates is still needed: the binary speaks TLS to the sites it audits,
# and a static binary brings no trust store with it.
# ---------------------------------------------------------------------------
FROM oven/bun:1 AS runner
WORKDIR /app

RUN apt-get update \
  && apt-get install -y --no-install-recommends ca-certificates \
  && rm -rf /var/lib/apt/lists/*

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV HSC_BIN=/usr/local/bin/nextjs-seo-prerender

COPY --from=audit-builder /out/nextjs-seo-prerender /usr/local/bin/nextjs-seo-prerender

COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/drizzle ./drizzle
COPY --from=builder /app/worker ./worker
COPY --from=builder /app/db ./db
COPY --from=builder /app/lib ./lib
COPY --from=builder /app/package.json /app/tsconfig.json /app/next.config.ts /app/drizzle.config.ts ./

# `bun` is the image's own unprivileged user. The audit binary should never run
# as root: it parses HTML a stranger chose.
USER bun

EXPOSE 3000
ENV PORT=3000

# Overridden by the worker service in compose.yaml.
CMD ["bun", "run", "start"]
