PSA/ee/server/Dockerfile.build
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

168 lines
6.7 KiB
Docker
Executable File

# Start with a base image and install system dependencies.
# Pin to the production-known-good Node runtime. node:alpine floated to Node 26.2.0
# and broke bundled Vault provider initialization in the blue deployment.
FROM node:26.1.0-alpine AS base
RUN apk add --no-cache \
bash \
postgresql-client \
redis \
graphicsmagick \
imagemagick \
ghostscript \
curl \
nano
WORKDIR /app
# Stage for installing dependencies (cache-friendly)
FROM base AS deps
# Copy package files for both root and server parts of the project
COPY package.json package-lock.json ./
# .npmrc carries legacy-peer-deps=true (next-auth@5 beta wants nodemailer ^7,
# project uses ^8); without it this stage's `npm install` fails ERESOLVE on npm@11.
COPY .npmrc ./
COPY server/package.json ./server/
COPY ee/server/package.json ./ee/server/
COPY tsconfig.base.json ./
COPY server/src/invoice-templates/assemblyscript ./server/src/invoice-templates/assemblyscript
RUN npm install
## Ensure workspace installs for server and shared so node_modules exist per workspace
RUN npm install --workspace=server --workspace=shared
# Builder stage for compiling the application
FROM deps AS builder
# Build-only fallback secrets let NextAuth edge guards pass; real secrets are injected at runtime.
ARG NEXTAUTH_SECRET_BUILD="dev-placeholder-nextauth-secret-32"
ENV NEXTAUTH_SECRET=${NEXTAUTH_SECRET_BUILD}
ENV AUTH_SECRET=${NEXTAUTH_SECRET_BUILD}
# Copy all project files and build the server
COPY . .
WORKDIR /app
# Full install AFTER `COPY . .` so every workspace package (packages/*, @product/*,
# @alga-psa/*) is symlinked into node_modules. The deps-stage install ran before
# those dirs existed, so a shared-only relink leaves @product/chat (and siblings)
# unresolvable by the EE build (`Module not found: @product/chat/context`).
RUN npm install
# Build all upstream packages (shared + pre-built) via Nx (handles dependency ordering)
RUN npx nx build-deps server
ENV USE_PREBUILT="true"
# Copy EE files and build enterprise edition
COPY scripts/ ./scripts/
ENV NEXT_PUBLIC_EDITION=enterprise
RUN ./scripts/build-enterprise.sh
WORKDIR /app/server
# Create secrets directory and populate with secure placeholder values
RUN mkdir -p /app/secrets && \
echo "secure-admin-password-placeholder" > /app/secrets/postgres_password && \
echo "secure-app-password-placeholder" > /app/secrets/db_password_server && \
echo "secure-hocuspocus-password-placeholder" > /app/secrets/db_password_hocuspocus && \
echo "secure-redis-password-placeholder" > /app/secrets/redis_password && \
echo "secure-32char-auth-key-placeholder-xxxxx" > /app/secrets/alga_auth_key && \
echo "secure-32char-crypto-key-placeholder-xxxx" > /app/secrets/crypto_key && \
echo "secure-32char-token-key-placeholder-xxxx" > /app/secrets/token_secret_key && \
echo "secure-32char-nextauth-key-placeholder-xx" > /app/secrets/nextauth_secret && \
echo "secure-email-password-placeholder" > /app/secrets/email_password && \
echo "secure-oauth-client-id-placeholder" > /app/secrets/google_oauth_client_id && \
echo "secure-oauth-client-secret-placeholder" > /app/secrets/google_oauth_client_secret && \
echo "secure-gmail-client-id-placeholder" > /app/secrets/GOOGLE_CLIENT_ID && \
echo "secure-gmail-client-secret-placeholder" > /app/secrets/GOOGLE_CLIENT_SECRET && \
echo "secure-ms-client-id-placeholder" > /app/secrets/MICROSOFT_CLIENT_ID && \
echo "secure-ms-client-secret-placeholder" > /app/secrets/MICROSOFT_CLIENT_SECRET && \
chmod 600 /app/secrets/*
# Copy example environment file and set Enterprise Edition
COPY .env.example /app/.env
COPY .env.example /app/server/.env
RUN sed -i 's/NEXT_PUBLIC_EDITION=community/NEXT_PUBLIC_EDITION=enterprise/' /app/.env && \
sed -i 's/NEXT_PUBLIC_EDITION=community/NEXT_PUBLIC_EDITION=enterprise/' /app/server/.env
WORKDIR /app
RUN npm run build:ee
# Final production image with minimal runtime artifacts
FROM node:26.1.0-alpine
RUN apk add --no-cache bash \
postgresql-client \
redis \
graphicsmagick \
imagemagick \
ghostscript \
curl \
nano \
chromium \
nss \
freetype \
freetype-dev \
harfbuzz \
ca-certificates \
ttf-freefont
WORKDIR /app
COPY tsconfig.base.json ./
COPY server/setup /app/server/setup
COPY .env.example /app/.env
COPY .env.example /app/server/.env
RUN sed -i 's/NEXT_PUBLIC_EDITION=community/NEXT_PUBLIC_EDITION=enterprise/' /app/.env && \
sed -i 's/NEXT_PUBLIC_EDITION=community/NEXT_PUBLIC_EDITION=enterprise/' /app/server/.env
# Copy built application and node_modules from earlier stages -- minimalist approach
COPY --from=builder /app/shared ./shared
COPY --from=builder /app/server/.next ./server/.next
COPY --from=builder /app/server/public ./server/public
COPY --from=builder /app/server/next.config.mjs ./server/
COPY --from=builder /app/server/tsconfig.json ./server/
COPY --from=builder /app/server/package.json ./server/
COPY --from=builder /app/package.json ./
COPY --from=builder /app/package-lock.json ./
COPY --from=builder /app/server/knexfile.cjs ./server/
COPY --from=builder /app/server/index.ts ./server/
COPY --from=builder /app/server/migrations/ ./server/migrations/
COPY --from=builder /app/server/seeds/ ./server/seeds/
COPY --from=builder /app/server/src/ ./server/src/
# server/scripts holds runtime entrypoints invoked at boot, notably
# create-tenant.ts which the appliance bootstrap runs to seed the initial
# tenant/admin. Without it the appliance install fails ERR_MODULE_NOT_FOUND.
COPY --from=builder /app/server/scripts/ ./server/scripts/
COPY --from=builder /app/secrets ./secrets
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/server/node_modules ./server/node_modules
# Copy EE migrations (they get merged during build-enterprise.sh)
COPY --from=builder /app/ee/server/migrations/ ./server/migrations/
# Copy core package.json for version info
COPY packages/core/package.json /app/packages/core/package.json
COPY server/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
# Ensure tsx is available on PATH at runtime for `npm start`
RUN npm install -g tsx
# Create build timestamp for verification
RUN echo "BUILD_TIME=$(date)" > /app/build-info.txt && \
echo "BUILD_EPOCH=$(date +%s)" >> /app/build-info.txt
EXPOSE 3000
# Environment configuration
ENV NODE_ENV=production
ENV NEXT_PUBLIC_EDITION=enterprise
# Puppeteer chromium configuration
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
# Secret provider configuration
# Default configuration for composite secret system
# Can be overridden in docker-compose or deployment environments
ENV SECRET_READ_CHAIN="env,filesystem"
ENV SECRET_WRITE_PROVIDER="filesystem"
ENTRYPOINT ["/app/entrypoint.sh"]