Refactor Dockerfiles and enhance Next.js configuration for improved build and security

- Updated Dockerfiles for BFF and Portal to optimize dependency installation and build processes, focusing on specific package filters.
- Enhanced Next.js configuration to improve security headers and Content Security Policy for development environments.
- Adjusted Docker Compose files to support dynamic image tagging for better version control.
- Cleaned up deployment scripts to include environment variable management for image tagging.
This commit is contained in:
barsa 2025-12-10 18:42:33 +09:00
parent bc5c7c9bd4
commit ce7c7773cd
7 changed files with 53 additions and 17 deletions

View File

@ -24,15 +24,16 @@ RUN apk add --no-cache python3 make g++ openssl libc6-compat \
WORKDIR /app
# Copy manifests first for dependency caching
# Copy manifests first for dependency caching (all workspace packages)
COPY .npmrc pnpm-workspace.yaml package.json pnpm-lock.yaml ./
COPY packages/domain/package.json ./packages/domain/
COPY apps/bff/package.json ./apps/bff/
COPY packages/domain/package.json ./packages/domain/package.json
COPY apps/bff/package.json ./apps/bff/package.json
COPY apps/portal/package.json ./apps/portal/package.json
# Install all dependencies with cache mount (separate layer for better caching)
# Install only the packages needed for the BFF (domain + bff)
ENV HUSKY=0
RUN --mount=type=cache,id=pnpm-bff,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
pnpm install --frozen-lockfile --filter @customer-portal/domain... --filter @customer-portal/bff...
# =============================================================================
# Stage 2: Builder
@ -47,7 +48,9 @@ COPY packages/domain/ ./packages/domain/
COPY apps/bff/ ./apps/bff/
# Build: domain → Prisma generate → BFF (single RUN for better layer efficiency)
RUN pnpm --filter @customer-portal/domain build \
# Clean tsbuildinfo to force fresh emit; checked-in files can skip output otherwise
RUN rm -f apps/bff/tsconfig*.tsbuildinfo \
&& pnpm --filter @customer-portal/domain build \
&& pnpm --filter @customer-portal/bff exec prisma generate \
&& pnpm --filter @customer-portal/bff build
@ -84,8 +87,10 @@ ENV PRISMA_SCHEMA_PATH=/app/prisma/schema.prisma
COPY --from=builder --chown=nestjs:nodejs /app/deploy ./
# Regenerate Prisma client for production paths and cleanup
RUN rm -rf node_modules/.prisma \
&& npx --yes prisma@${PRISMA_VERSION} generate --schema=${PRISMA_SCHEMA_PATH} \
RUN npm install -g prisma@${PRISMA_VERSION} \
&& rm -rf node_modules/.prisma \
&& prisma generate --schema=${PRISMA_SCHEMA_PATH} \
&& mkdir -p /app/node_modules/.prisma \
# Create symlink for backward compatibility with any hardcoded paths
&& mkdir -p /app/apps/bff/prisma \
&& ln -sf /app/prisma/schema.prisma /app/apps/bff/prisma/schema.prisma \

View File

@ -23,15 +23,16 @@ RUN apk add --no-cache libc6-compat \
WORKDIR /app
# Copy manifests first for dependency caching
# Copy manifests first for dependency caching (all workspace packages)
COPY .npmrc pnpm-workspace.yaml package.json pnpm-lock.yaml ./
COPY packages/domain/package.json ./packages/domain/
COPY apps/portal/package.json ./apps/portal/
COPY packages/domain/package.json ./packages/domain/package.json
COPY apps/portal/package.json ./apps/portal/package.json
COPY apps/bff/package.json ./apps/bff/package.json
# Install dependencies with cache mount (unique id per app for better caching)
# Install only the packages needed for the portal (domain + portal)
ENV HUSKY=0
RUN --mount=type=cache,id=pnpm-portal,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
pnpm install --frozen-lockfile --filter @customer-portal/domain... --filter @customer-portal/portal...
# =============================================================================
# Stage 2: Builder

View File

@ -47,11 +47,37 @@ const nextConfig = {
async headers() {
const isDev = process.env.NODE_ENV === "development";
const connectSources = ["'self'", "https:"];
if (isDev) {
connectSources.push("http://localhost:*");
const devConnectSources = ["'self'", "https:", "http://localhost:*", "ws://localhost:*"];
const devScriptSrc = ["'self'", "'unsafe-inline'", "'unsafe-eval'", "blob:"].join(" ");
return [
{
source: "/(.*)",
headers: [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "X-XSS-Protection", value: "1; mode=block" },
{
key: "Content-Security-Policy",
value: [
"default-src 'self'",
`script-src ${devScriptSrc}`,
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self' data:",
`connect-src ${devConnectSources.join(" ")}`,
"frame-ancestors 'none'",
].join("; "),
},
],
},
];
}
const connectSources = ["'self'", "https:"];
return [
{
source: "/(.*)",

View File

@ -10,7 +10,7 @@ services:
# Frontend (Next.js)
# ---------------------------------------------------------------------------
frontend:
image: ${FRONTEND_IMAGE:-portal-frontend:latest}
image: ${FRONTEND_IMAGE:-portal-frontend}:${IMAGE_TAG:-latest}
container_name: portal-frontend
ports:
- "127.0.0.1:${FRONTEND_PORT:-3000}:3000"
@ -35,7 +35,7 @@ services:
# Backend (NestJS BFF)
# ---------------------------------------------------------------------------
backend:
image: ${BACKEND_IMAGE:-portal-backend:latest}
image: ${BACKEND_IMAGE:-portal-backend}:${IMAGE_TAG:-latest}
container_name: portal-backend
ports:
- "127.0.0.1:${BACKEND_PORT:-4000}:4000"

View File

@ -0,0 +1 @@
8c26832b5a788235f2fb461eeeb10a33f34f40830d04fb1235aed449b67ebe1c /home/barsa/projects/customer_portal/customer-portal/portal-backend.latest.tar.gz

View File

@ -0,0 +1 @@
8b0b76418ba09fc6cb3134db6ac87d350463f88fae6ffae4fd536111d15fa0cf /home/barsa/projects/customer_portal/customer-portal/portal-frontend.latest.tar.gz

View File

@ -292,6 +292,8 @@ while [[ $# -gt 0 ]]; do
esac
done
export IMAGE_TAG
# =============================================================================
# Main
# =============================================================================