2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
|
|
|
|
# Frontend (Portal) Dockerfile - Production Grade
|
|
|
|
|
# =============================================================================
|
|
|
|
|
# Uses Alpine throughout for consistency
|
|
|
|
|
# Next.js standalone output for minimal production image
|
|
|
|
|
# =============================================================================
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
ARG PNPM_VERSION=10.15.0
|
|
|
|
|
ARG NODE_VERSION=22
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
|
|
|
|
# Stage 1: Builder - Install dependencies and build Next.js
|
|
|
|
|
# =============================================================================
|
|
|
|
|
FROM node:${NODE_VERSION}-alpine AS builder
|
|
|
|
|
|
|
|
|
|
ARG PNPM_VERSION
|
|
|
|
|
|
|
|
|
|
# Install build dependencies
|
|
|
|
|
RUN apk add --no-cache libc6-compat \
|
|
|
|
|
&& corepack enable \
|
|
|
|
|
&& corepack prepare pnpm@${PNPM_VERSION} --activate
|
2025-08-20 18:02:50 +09:00
|
|
|
|
|
|
|
|
WORKDIR /app
|
|
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Copy workspace configuration first (better layer caching)
|
2025-12-02 10:05:11 +09:00
|
|
|
COPY .npmrc pnpm-workspace.yaml package.json pnpm-lock.yaml ./
|
2025-09-26 17:02:36 +09:00
|
|
|
COPY packages/domain/package.json ./packages/domain/
|
2025-08-21 15:24:40 +09:00
|
|
|
COPY apps/portal/package.json ./apps/portal/
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Install all dependencies
|
|
|
|
|
ENV HUSKY=0
|
|
|
|
|
RUN pnpm install --frozen-lockfile
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Copy source code
|
|
|
|
|
COPY tsconfig.json tsconfig.base.json ./
|
2025-09-26 17:02:36 +09:00
|
|
|
COPY packages/ ./packages/
|
2025-08-21 15:24:40 +09:00
|
|
|
COPY apps/portal/ ./apps/portal/
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Build domain package
|
|
|
|
|
RUN pnpm --filter @customer-portal/domain build
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 10:05:11 +09:00
|
|
|
# Build-time environment variables (baked into Next.js client bundle)
|
|
|
|
|
ARG NEXT_PUBLIC_API_BASE=/api
|
|
|
|
|
ARG NEXT_PUBLIC_APP_NAME="Customer Portal"
|
|
|
|
|
ARG NEXT_PUBLIC_APP_VERSION=1.0.0
|
|
|
|
|
|
|
|
|
|
ENV NODE_ENV=production \
|
|
|
|
|
NEXT_PUBLIC_API_BASE=${NEXT_PUBLIC_API_BASE} \
|
|
|
|
|
NEXT_PUBLIC_APP_NAME=${NEXT_PUBLIC_APP_NAME} \
|
|
|
|
|
NEXT_PUBLIC_APP_VERSION=${NEXT_PUBLIC_APP_VERSION}
|
|
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Build Next.js (creates standalone output)
|
|
|
|
|
RUN pnpm --filter @customer-portal/portal build
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# =============================================================================
|
|
|
|
|
# Stage 2: Production - Minimal runtime image
|
|
|
|
|
# =============================================================================
|
|
|
|
|
FROM node:${NODE_VERSION}-alpine AS production
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
LABEL org.opencontainers.image.title="Customer Portal Frontend" \
|
|
|
|
|
org.opencontainers.image.description="Customer Portal Application" \
|
|
|
|
|
org.opencontainers.image.vendor="Customer Portal"
|
2025-08-21 15:24:40 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
# Runtime dependencies only
|
|
|
|
|
RUN apk add --no-cache \
|
|
|
|
|
dumb-init \
|
|
|
|
|
wget \
|
|
|
|
|
curl \
|
|
|
|
|
libc6-compat \
|
|
|
|
|
&& rm -rf /var/cache/apk/*
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 10:05:11 +09:00
|
|
|
# Create non-root user
|
2025-08-21 15:24:40 +09:00
|
|
|
RUN addgroup --system --gid 1001 nodejs && \
|
|
|
|
|
adduser --system --uid 1001 nextjs
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 11:06:54 +09:00
|
|
|
WORKDIR /app
|
|
|
|
|
|
|
|
|
|
# Copy Next.js standalone build (includes all bundled dependencies)
|
2025-08-21 15:24:40 +09:00
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/portal/.next/standalone ./
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/portal/.next/static ./apps/portal/.next/static
|
|
|
|
|
COPY --from=builder --chown=nextjs:nodejs /app/apps/portal/public ./apps/portal/public
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-12-02 10:05:11 +09:00
|
|
|
RUN mkdir -p /app/logs && chown -R nextjs:nodejs /app
|
2025-09-01 15:11:42 +09:00
|
|
|
|
2025-08-20 18:02:50 +09:00
|
|
|
USER nextjs
|
|
|
|
|
|
|
|
|
|
EXPOSE 3000
|
|
|
|
|
|
2025-12-02 10:05:11 +09:00
|
|
|
ENV NODE_ENV=production \
|
|
|
|
|
NEXT_TELEMETRY_DISABLED=1 \
|
|
|
|
|
PORT=3000 \
|
|
|
|
|
HOSTNAME="0.0.0.0"
|
2025-08-20 18:02:50 +09:00
|
|
|
|
2025-08-21 15:24:40 +09:00
|
|
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
|
|
|
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
|
|
|
|
|
2025-09-01 15:11:42 +09:00
|
|
|
ENTRYPOINT ["dumb-init", "--"]
|
|
|
|
|
CMD ["node", "apps/portal/server.js"]
|