ARG HOST
ARG PORT
ARG LOG_LEVEL

# Invariants: production dependencies are installed on Debian, independently of
# compiled output. Keep workspace manifests and publish-directory links intact.
FROM node:20-alpine AS manifests

WORKDIR /srv/xpert

COPY --chown=node:node apps/api/package.json ./apps/api/
COPY --chown=node:node packages/contracts/package.json ./packages/contracts/
COPY --chown=node:node packages/common/package.json ./packages/common/
COPY --chown=node:node packages/config/package.json ./packages/config/
COPY --chown=node:node packages/auth/package.json ./packages/auth/
COPY --chown=node:node packages/server/package.json ./packages/server/
COPY --chown=node:node packages/server-ai/package.json ./packages/server-ai/
COPY --chown=node:node packages/plugin-sdk/package.json ./packages/plugin-sdk/
COPY --chown=node:node packages/shadcn-ui/package.json ./packages/shadcn-ui/
COPY --chown=node:node packages/desktop-protocol/package.json ./packages/desktop-protocol/
COPY --chown=node:node packages/plugins/cli-model-profiles/package.json ./packages/plugins/cli-model-profiles/
COPY --chown=node:node packages/plugins/draft/package.json ./packages/plugins/draft/
COPY --chown=node:node packages/plugins/github-integration/package.json ./packages/plugins/github-integration/
COPY --chown=node:node packages/plugins/vlm-default/package.json ./packages/plugins/vlm-default/

COPY --chown=node:node pnpm-workspace.yaml ./
COPY --chown=node:node .npmrc ./

FROM node:20-alpine AS build-dependencies

ARG NODE_OPTIONS="--max-old-space-size=4096"
ENV NODE_OPTIONS=${NODE_OPTIONS}

LABEL maintainer="meta.digital.cloud@gmail.com"
LABEL org.opencontainers.image.source=https://github.com/xpert-ai/xpert

ENV CI=true

RUN apk --update add bash jq python3 make g++ && npm i -g npm && \
    corepack enable && corepack prepare pnpm@10.24.0 --activate
WORKDIR /srv/xpert
RUN chown node:node /srv/xpert
USER node:node

COPY --chown=node:node --from=manifests /srv/xpert/ ./
COPY --chown=node:node .deploy/api/package.json ./
COPY --chown=node:node .deploy/api/pnpm-lock.build.yaml ./pnpm-lock.yaml
COPY --chown=node:node .eslintrc.json ./
COPY --chown=node:node .nxignore ./

RUN pnpm install --frozen-lockfile

FROM build-dependencies AS build

COPY --chown=node:node nx.json ./
COPY --chown=node:node tsconfig.base.json ./
COPY --chown=node:node packages ./packages
COPY --chown=node:node apps/api ./apps/api
COPY --chown=node:node .deploy/api/build.mjs .deploy/api/dependencies.cjs .deploy/api/package.json .deploy/api/package-prod.json .deploy/api/pnpm-lock.build.yaml .deploy/api/pnpm-lock.production.yaml .deploy/api/database-migrations.json ./.deploy/api/
RUN rm -rf packages/angular packages/ui packages/sandbox-runtime packages/nsjail-runner packages/plugins/local-shell-sandbox

# All package manifests were installed above; reject any source-layout drift.
RUN node .deploy/api/dependencies.cjs check && \
    pnpm install --lockfile-only --frozen-lockfile --ignore-scripts --offline
RUN node --test apps/api/config/buildable-libraries.test.cjs
RUN node .deploy/api/build.mjs
RUN node .deploy/api/dependencies.cjs prepare-runtime /srv/xpert/api-runtime && \
    cd /srv/xpert/api-runtime && \
    pnpm install --prod --lockfile-only --frozen-lockfile --ignore-scripts --offline

#////////////////////////////////////////////////////////////////////////////////
FROM node:20 AS production-dependencies

ENV NODE_OPTIONS="--max-old-space-size=2048" \
    NODE_ENV=production \
    API_BASE_URL=http://localhost:3000 \
    CODE_XPERT_URL=https://code.xpertai.cn/ \
    DEEP_RESEARCH_URL=https://research.xpertai.cn/ \
    DATA_ONTOLOGY_URL=https://data.xpertai.cn/ \
    SENTRY_DSN= \
    DB_HOST=db \
    DB_NAME=postgres \
    DB_PORT=5432 \
    DB_USER= \
    DB_PASS= \
    DB_TYPE=sqlite \
    DB_SSL_MODE= \
    HOST=0.0.0.0 \
    PORT=3000 \
    DEMO=false \
    LOG_LEVEL=

# Install native build tools for runtime dependencies such as isolated-vm.
RUN apt-get -o Acquire::Retries=5 -o Acquire::http::Timeout=30 update && \
    apt-get -o Acquire::Retries=5 -o Acquire::http::Timeout=30 install -y --no-install-recommends \
      sudo \
      build-essential \
      python3 \
      python3-pip && \
    rm -rf /var/lib/apt/lists/*
RUN usermod -aG sudo node
RUN echo "node ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/node

# Install python uvx
RUN python3 -m pip install uv --break-system-packages

WORKDIR /srv/xpert

RUN npm install pm2 -g
RUN corepack enable && corepack prepare pnpm@10.24.0 --activate

# Source manifests and the production lock are the only application inputs to install.
COPY --chown=node:node --from=manifests /srv/xpert/packages ./packages
COPY --chown=node:node --from=manifests /srv/xpert/pnpm-workspace.yaml /srv/xpert/.npmrc ./
COPY --chown=node:node .deploy/api/package-prod.json ./package.json
COPY --chown=node:node .deploy/api/pnpm-lock.production.yaml ./pnpm-lock.yaml
RUN chown node:node /srv/xpert
USER node:node
RUN pnpm install --prod --frozen-lockfile

FROM production-dependencies AS production

COPY --chown=node:node wait ./
# Assembly preserves nested publish directories and uses source dependency
# declarations with compiler-generated entry points and the production lock.
COPY --chown=node:node --from=build /srv/xpert/api-runtime ./

COPY --chown=node:node .deploy/api/entrypoint.compose.sh ./
COPY --chown=node:node .deploy/api/entrypoint.prod.sh ./
COPY --chown=node:node .deploy/api/healthcheck.cjs ./
COPY --chown=node:node .deploy/api/check-native-modules.cjs ./
RUN chmod +x wait entrypoint.compose.sh entrypoint.prod.sh

RUN touch ormlogs.log

# Exercise native bindings as the runtime user, not just dependency resolution.
RUN node --no-node-snapshot check-native-modules.cjs
RUN node main.js --command schema-check

EXPOSE ${PORT}

HEALTHCHECK --interval=30s --timeout=15s --start-period=60s --retries=3 CMD ["node", "healthcheck.cjs"]

ENTRYPOINT [ "sh", "./entrypoint.prod.sh" ]
CMD [ "pm2-runtime", "main.js" ]

FROM production AS candidate
