diff --git a/.dockerignore b/.dockerignore index c287cb1a1..c42297230 100644 --- a/.dockerignore +++ b/.dockerignore @@ -28,10 +28,8 @@ dist/ !packages/**/dist/** # Environment files -.env.local -.env.development.local -.env.test.local -.env.production.local +.env* +!.env.example # IDE and editor files .vscode/ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6f0bacb56..c8526e403 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ on: workflow_dispatch: env: - NODE_VERSION: '20' + NODE_VERSION: '22' jobs: unit-tests: @@ -17,7 +17,7 @@ jobs: services: postgres: - image: postgres:16 + image: postgres:17-alpine env: POSTGRES_PASSWORD: postgres POSTGRES_DB: pagespace_test diff --git a/apps/processor/Dockerfile b/apps/processor/Dockerfile index 9bd2939fe..5d80f257f 100644 --- a/apps/processor/Dockerfile +++ b/apps/processor/Dockerfile @@ -27,9 +27,8 @@ COPY packages/db/package.json ./packages/db/ COPY packages/lib/package.json ./packages/lib/ COPY apps/processor/package.json ./apps/processor/ -# Install all dependencies -# Install dependencies (allow lockfile update since processor deps changed) -RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm config set store-dir /pnpm/store && pnpm install --no-frozen-lockfile --prod=false +# Install dependencies +RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm config set store-dir /pnpm/store && pnpm install --frozen-lockfile --prod=false # Now copy source code AFTER dependencies are installed COPY tsconfig.json ./ diff --git a/apps/realtime/Dockerfile b/apps/realtime/Dockerfile index 5508699b1..b5177dac7 100644 --- a/apps/realtime/Dockerfile +++ b/apps/realtime/Dockerfile @@ -1,40 +1,58 @@ # syntax=docker/dockerfile:1.6 -# This Dockerfile runs the realtime service. -# It uses the same pattern as the working migrate container. -FROM node:22.17.0-alpine +# Multi-stage build for the realtime Socket.IO service -# Set working directory +# Stage 1: Install dependencies and build +FROM node:22.17.0-alpine AS builder WORKDIR /app -# Install basic tools and configure npm -RUN apk add --no-cache git && \ - npm config set fetch-timeout 300000 && \ - npm config set fetch-retry-maxtimeout 120000 && \ - npm config set fetch-retry-mintimeout 10000 - -# Enable corepack and prepare specific pnpm version RUN corepack enable && \ (corepack prepare pnpm@10.13.1 --activate || corepack prepare pnpm@10.13.1 --activate || corepack prepare pnpm@10.13.1 --activate) -# Copy package files first for better Docker layer caching COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ COPY packages/db/package.json ./packages/db/ COPY packages/lib/package.json ./packages/lib/ COPY apps/web/package.json ./apps/web/ COPY apps/realtime/package.json ./apps/realtime/ -# Install ALL dependencies for the entire monorepo RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm config set store-dir /pnpm/store && pnpm install --frozen-lockfile --prod=false -# Copy only the source code needed (avoid copying node_modules) -COPY packages ./packages -COPY apps ./apps +COPY types ./types +COPY packages/db ./packages/db +COPY packages/lib ./packages/lib +COPY apps/realtime ./apps/realtime COPY tsconfig.json ./ -# Copy .env file for environment variables -COPY .env ./ +# Build shared packages and the realtime service +RUN pnpm --filter @pagespace/db build && \ + pnpm --filter @pagespace/lib build && \ + pnpm --filter realtime build + +# Stage 2: Production runner +FROM node:22.17.0-alpine AS runner +WORKDIR /app + +RUN corepack enable && \ + (corepack prepare pnpm@10.13.1 --activate || corepack prepare pnpm@10.13.1 --activate || corepack prepare pnpm@10.13.1 --activate) + +# Copy manifests and lockfile for production install +COPY --from=builder /app/package.json /app/pnpm-lock.yaml /app/pnpm-workspace.yaml ./ +COPY --from=builder /app/packages/db/package.json ./packages/db/ +COPY --from=builder /app/packages/lib/package.json ./packages/lib/ +COPY --from=builder /app/apps/web/package.json ./apps/web/ +COPY --from=builder /app/apps/realtime/package.json ./apps/realtime/ + +# Install production-only dependencies +RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm config set store-dir /pnpm/store && pnpm install --frozen-lockfile --prod + +# Copy only compiled runtime artifacts from builder +COPY --from=builder /app/packages/db/dist ./packages/db/dist +COPY --from=builder /app/packages/lib/dist ./packages/lib/dist +COPY --from=builder /app/apps/realtime/dist ./apps/realtime/dist + +ENV NODE_ENV=production + +USER node EXPOSE 3001 -# Run the realtime service with tsx -CMD ["pnpm", "--filter", "realtime", "start"] +CMD ["node", "apps/realtime/dist/index.js"] diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 82bfe6791..7b57d4199 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -47,8 +47,7 @@ ENV NEXT_PUBLIC_GOOGLE_OAUTH_IOS_CLIENT_ID=$NEXT_PUBLIC_GOOGLE_OAUTH_IOS_CLIENT_ # Next.js collects telemetry data by default. # Learn more here: https://nextjs.org/telemetry -# Uncomment the following line in case you want to disable telemetry. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED=1 # We are installing devDependencies via the --prod=false flag, so this is not needed # ENV NODE_ENV=development @@ -65,8 +64,7 @@ FROM node:22.17.0-alpine AS runner WORKDIR /app ENV NODE_ENV=production -# Uncomment the following line in case you want to disable telemetry. -# ENV NEXT_TELEMETRY_DISABLED 1 +ENV NEXT_TELEMETRY_DISABLED=1 # Use the existing node user (UID 1000) from the base image # This matches the processor container's UID for shared volume access diff --git a/apps/web/Dockerfile.migrate b/apps/web/Dockerfile.migrate index d9ed623f2..5327b11ea 100644 --- a/apps/web/Dockerfile.migrate +++ b/apps/web/Dockerfile.migrate @@ -34,6 +34,3 @@ COPY tsconfig.json ./ # Build the database package to ensure latest schema changes are compiled RUN pnpm --filter @pagespace/db build - -# Copy .env file for tsx --env-file -COPY .env ./ diff --git a/apps/web/Dockerfile.seed b/apps/web/Dockerfile.seed index 3326025cf..e9a3faf50 100644 --- a/apps/web/Dockerfile.seed +++ b/apps/web/Dockerfile.seed @@ -26,8 +26,5 @@ COPY packages ./packages COPY apps ./apps COPY tsconfig.json ./ -# Copy .env file for tsx --env-file -COPY .env ./ - # Run seed -CMD ["pnpm", "--filter", "@pagespace/db", "db:seed"] \ No newline at end of file +CMD ["pnpm", "--filter", "@pagespace/db", "db:seed"] diff --git a/apps/web/Dockerfile.worker b/apps/web/Dockerfile.worker index 8e80da642..35695ce66 100644 --- a/apps/web/Dockerfile.worker +++ b/apps/web/Dockerfile.worker @@ -39,9 +39,9 @@ COPY --from=deps --chown=worker:nodejs /app . USER worker -# Health check +# Health check - verify the main process (PID 1) is alive HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ - CMD node -e "console.log('Worker health check')" || exit 1 + CMD node -e "try { process.kill(1, 0); } catch(e) { process.exit(1); }" # Run the worker using tsx -CMD ["pnpm", "tsx", "apps/web/src/workers/file-processor.ts"] \ No newline at end of file +CMD ["pnpm", "tsx", "apps/web/src/workers/file-processor.ts"]