# syntax=docker/dockerfile:1.7
#
# Self-hosted CaptureFlow without Cloudflare: SQLite + local disk under /data.
# One image: the web app, with the admin app beside it under /admin.
#   docker build --target web -t captureflow .
# See docker-compose.yml and apps/docs/self-hosting/docker.md.

ARG NODE_IMAGE=node:24.15.0-bookworm-slim@sha256:4e6b70dd6cbfc88c8157ba19aa3d9f9cce6ba4703576d55459e45efcbc9c5f5d

FROM ${NODE_IMAGE} AS build
ENV PNPM_HOME=/pnpm PATH=/pnpm:$PATH NEXT_TELEMETRY_DISABLED=1 NODE_OPTIONS=--max-old-space-size=1536 UV_THREADPOOL_SIZE=1 RAYON_NUM_THREADS=1
RUN corepack enable
WORKDIR /repo

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm fetch --ignore-scripts

COPY . .
RUN node -e "const v=require('./apps/extension/package.json').version;console.log('Verified input extension version:',v);if(v!=='0.2.9')process.exit(1)"
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm install --offline --frozen-lockfile --ignore-scripts --child-concurrency=1 \
      --filter "@captureflow/web..." --filter "@captureflow/selfhost-admin..." --filter "@captureflow/extension..."

# NEXT_PUBLIC_* are inlined at build; the sentinel origin is swapped for
# APP_URL when the container starts (apps/web/selfhost/origin.ts).
# Your own extension's store listing, for the dashboard's "Add to Chrome" link.
ARG NEXT_PUBLIC_CHROME_WEBSTORE_URL
ENV NEXT_PUBLIC_CHROME_WEBSTORE_URL=${NEXT_PUBLIC_CHROME_WEBSTORE_URL}
ENV CAPTUREFLOW_STANDALONE=1 \
    NEXT_PUBLIC_CAPTUREFLOW_NO_ANALYTICS=1 \
    NEXT_PUBLIC_MARKETING_SITE_URL=https://captureflow-selfhost-origin.invalid \
    NEXT_PUBLIC_APP_WEB_SITE_URL=https://captureflow-selfhost-origin.invalid \
    NEXT_PUBLIC_R2_PUBLIC_BASE_URL=https://captureflow-selfhost-origin.invalid/media
# Release compiler memory before checking types; both checks must pass before
# static generation or image packaging. Never disable TypeScript validation.
RUN pnpm --filter @captureflow/web exec next build --experimental-build-mode compile
RUN pnpm --filter @captureflow/web exec tsc --noEmit --incremental false
RUN pnpm --filter @captureflow/web exec next build --experimental-build-mode generate && pnpm --filter @captureflow/web selfhost:build
RUN pnpm --filter @captureflow/selfhost-admin exec next build --experimental-build-mode compile
RUN pnpm --filter @captureflow/selfhost-admin exec tsc --noEmit --incremental false
RUN pnpm --filter @captureflow/selfhost-admin exec next build --experimental-build-mode generate && pnpm --filter @captureflow/selfhost-admin selfhost:build

# Build the private extension sequentially, with the same pinned identity.
RUN node -e "if(require('./apps/extension/package.json').version!=='0.2.9')process.exit(1)" && \
    WXT_WEB_BASE=https://recordings.melnyresults.com WXT_EXT_KEY="$(cat apps/extension/public-key.txt)" \
    pnpm --filter @captureflow/extension exec wxt zip && \
    node -e "const m=require('./apps/extension/.output/chrome-mv3/manifest.json');if(m.version!=='0.2.9'||JSON.stringify(m.host_permissions)!==JSON.stringify(['https://recordings.melnyresults.com/*']))process.exit(1)" && \
    mkdir -p apps/web/public/source && \
    cp apps/extension/.output/*-chrome.zip apps/web/public/source/melny-recorder-extension.zip

FROM ${NODE_IMAGE} AS runtime
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 DATA_DIR=/data
WORKDIR /app
RUN mkdir -p /data && chown node:node /data /app
VOLUME /data

FROM runtime AS web
ENV PORT=3000 CAPTUREFLOW_APP_DIR=/app/apps/web
COPY --from=build --chown=node:node /repo/apps/web/.next/standalone ./
COPY --from=build --chown=node:node /repo/apps/web/.next/static ./apps/web/.next/static
COPY --from=build --chown=node:node /repo/apps/web/public ./apps/web/public
COPY --from=build --chown=node:node /repo/apps/web/migrations ./apps/web/migrations
COPY --from=build --chown=node:node /repo/apps/web/selfhost/dist/server.mjs ./apps/web/selfhost-server.mjs
COPY --from=build --chown=node:node /repo/apps/selfhost-admin/.next/standalone ./
COPY --from=build --chown=node:node /repo/apps/selfhost-admin/.next/static ./apps/selfhost-admin/.next/static
COPY --from=build --chown=node:node /repo/apps/selfhost-admin/selfhost/dist/server.mjs ./apps/selfhost-admin/selfhost-server.mjs
USER node
EXPOSE 3000
HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=5 \
  CMD node -e "fetch('http://127.0.0.1:'+process.env.PORT+'/api/health').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"
CMD ["node", "--disable-warning=ExperimentalWarning", "apps/web/selfhost-server.mjs"]
