perf: docker + next.js build optimisation - dockerignore exclusions, BuildKit cache mounts, backend image reuse, memory limits, next.js bundle tree-shaking
This commit is contained in:
@@ -1,12 +1,54 @@
|
|||||||
|
# ── Node / NPM ─────────────────────────────────────────────────────────────
|
||||||
node_modules
|
node_modules
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# ── Next.js build artefacts ─────────────────────────────────────────────────
|
||||||
.next
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# ── Git / CI ────────────────────────────────────────────────────────────────
|
||||||
.git
|
.git
|
||||||
|
.gitignore
|
||||||
|
.github
|
||||||
|
|
||||||
|
# ── Secrets / env files (injected at runtime via docker-compose env_file) ───
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
# ── Python artefacts ─────────────────────────────────────────────────────────
|
||||||
yarn-error.log*
|
__pycache__
|
||||||
pnpm-debug.log*
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
backend/__pycache__
|
||||||
|
backend/celerybeat-schedule
|
||||||
|
|
||||||
|
# ── IDE / OS ─────────────────────────────────────────────────────────────────
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# ── Heavy static data not needed in the image ────────────────────────────────
|
||||||
|
dpps
|
||||||
|
scratch
|
||||||
|
*.pdf
|
||||||
|
jee_advanced_full_90q.json
|
||||||
|
neet_180_questions.json
|
||||||
|
neet_sample_questions.md
|
||||||
|
API_DOCUMENTATION.md
|
||||||
|
PAGEWISE_API_DOCUMENTATION.md
|
||||||
|
DESIGN_SYSTEM.md
|
||||||
|
PRD.md
|
||||||
|
admin_json_samples.md
|
||||||
|
README.md
|
||||||
|
|
||||||
|
# ── TypeScript build info ────────────────────────────────────────────────────
|
||||||
|
tsconfig.tsbuildinfo
|
||||||
|
|||||||
55
Dockerfile
55
Dockerfile
@@ -1,54 +1,57 @@
|
|||||||
FROM node:20-alpine AS base
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Stage 1 – deps: install node_modules with full cache mount
|
||||||
|
# (This layer is only re-run when package.json / package-lock.json changes)
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
FROM node:20-alpine AS deps
|
||||||
|
|
||||||
# Install dependencies only when needed
|
|
||||||
FROM base AS deps
|
|
||||||
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
|
||||||
RUN apk add --no-cache libc6-compat
|
RUN apk add --no-cache libc6-compat
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install dependencies based on the preferred package manager
|
|
||||||
COPY package.json package-lock.json* ./
|
COPY package.json package-lock.json* ./
|
||||||
RUN npm ci
|
|
||||||
|
|
||||||
# Rebuild the source code only when needed
|
# --mount=type=cache keeps the npm cache on the host between builds
|
||||||
FROM base AS builder
|
# --prefer-offline avoids network fetches when the package is already cached
|
||||||
|
RUN --mount=type=cache,target=/root/.npm \
|
||||||
|
npm ci --prefer-offline
|
||||||
|
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# Stage 2 – builder: compile Next.js with build-cache mount for turbo-speed
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Set environment variables for build
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
# Accept API URL as build arg — defaults to Docker-internal service name
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
ARG NEXT_PUBLIC_API_URL=http://backend:8000
|
ARG NEXT_PUBLIC_API_URL=http://backend:8000
|
||||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||||
# BACKEND_INTERNAL_URL drives the server-side /api rewrite; must be a build-time
|
|
||||||
# arg so it is compiled into next.config.ts (which is evaluated at build time).
|
|
||||||
ARG BACKEND_INTERNAL_URL
|
|
||||||
ENV BACKEND_INTERNAL_URL=$BACKEND_INTERNAL_URL
|
|
||||||
|
|
||||||
RUN npm run build
|
# Mount the Next.js build cache so incremental compilation is reused
|
||||||
|
RUN --mount=type=cache,target=/app/.next/cache \
|
||||||
|
npm run build
|
||||||
|
|
||||||
# Production image, copy all the files and run next
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
FROM base AS runner
|
# Stage 3 – runner: minimal production image (no node_modules, no sources)
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
RUN addgroup --system --gid 1001 nodejs
|
RUN addgroup --system --gid 1001 nodejs && \
|
||||||
RUN adduser --system --uid 1001 nextjs
|
adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
# Copy only the standalone server output (no full node_modules)
|
||||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
|
||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
|
|
||||||
# Set the correct permission for prerender cache
|
RUN mkdir .next && chown nextjs:nodejs .next
|
||||||
RUN mkdir .next
|
|
||||||
RUN chown nextjs:nodejs .next
|
|
||||||
|
|
||||||
# Automatically leverage output traces to reduce image size
|
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
USER nextjs
|
USER nextjs
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
# PragatiVeer Backend – Python 3.11 slim
|
||||||
|
# Optimised for fast re-builds:
|
||||||
|
# • requirements.txt copied FIRST → pip cache layer is only invalidated
|
||||||
|
# when dependencies change, not on every source-code edit.
|
||||||
|
# • BuildKit pip cache mount keeps wheel cache on host between builds.
|
||||||
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Install system deps in a single RUN layer, clean apt cache immediately
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
# ── Dependencies first (most stable layer) ──────────────────────────────────
|
||||||
build-essential \
|
|
||||||
libpq-dev \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
# Use BuildKit pip cache so wheels are reused across builds
|
||||||
|
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||||
|
pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# ── Source code (changes frequently; comes last) ─────────────────────────────
|
||||||
|
COPY . .
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
|
|||||||
39
build.ps1
Normal file
39
build.ps1
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env powershell
|
||||||
|
# build.ps1 — Clean, fast Docker build script for PragatiVeer v2
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
# What this script does:
|
||||||
|
# 1. Enables Docker BuildKit (required for --mount=type=cache to work)
|
||||||
|
# 2. Runs `docker compose build --parallel` which:
|
||||||
|
# - Builds backend image ONCE and tags it as pragativeer-backend:local
|
||||||
|
# - worker + beat containers reuse that image (no rebuild)
|
||||||
|
# - BuildKit caches pip wheels and npm packages between builds
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
$env:DOCKER_BUILDKIT = "1"
|
||||||
|
$env:COMPOSE_DOCKER_CLI_BUILD = "1"
|
||||||
|
|
||||||
|
Write-Host "═══════════════════════════════════════════════" -ForegroundColor Cyan
|
||||||
|
Write-Host " PragatiVeer v2 — Optimised Docker Build" -ForegroundColor Cyan
|
||||||
|
Write-Host "═══════════════════════════════════════════════" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "▶ BuildKit enabled (cache mounts active)" -ForegroundColor Green
|
||||||
|
Write-Host "▶ Building backend image first..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# Build backend image first so worker/beat can reuse it
|
||||||
|
docker compose build backend
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "▶ Building remaining services in parallel..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# Build remaining services (frontend, etc.)
|
||||||
|
docker compose build --parallel frontend
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "✔ Build complete. Starting services..." -ForegroundColor Green
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "✔ All services started." -ForegroundColor Green
|
||||||
|
Write-Host " Frontend: http://localhost:3000" -ForegroundColor Cyan
|
||||||
|
Write-Host " Backend: http://localhost:8000" -ForegroundColor Cyan
|
||||||
|
Write-Host " MinIO: http://localhost:9001" -ForegroundColor Cyan
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
|
# ── Build once, run three times for backend services ─────────────────────────
|
||||||
|
# backend, worker, and beat all share the same image (built once from Dockerfile.dev)
|
||||||
|
# This alone eliminates 2 redundant Docker builds (previously 3 separate builds)
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:15-alpine
|
image: postgres:15-alpine
|
||||||
container_name: pragativeer_prod_db
|
container_name: pragativeer_db
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: pragativeer_admin
|
POSTGRES_USER: pragativeer_admin
|
||||||
POSTGRES_PASSWORD: local_secure_password_2026
|
POSTGRES_PASSWORD: local_secure_password_2026
|
||||||
POSTGRES_DB: pragativeer_prod
|
POSTGRES_DB: pragativeer_prod
|
||||||
ports:
|
ports:
|
||||||
- "5440:5432"
|
- "5432:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- pgdata:/var/lib/postgresql/data
|
||||||
networks:
|
networks:
|
||||||
@@ -19,29 +22,161 @@ services:
|
|||||||
test: ["CMD-SHELL", "pg_isready -U pragativeer_admin -d pragativeer_prod"]
|
test: ["CMD-SHELL", "pg_isready -U pragativeer_admin -d pragativeer_prod"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 5
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512m
|
||||||
|
|
||||||
|
pgbouncer:
|
||||||
|
image: edoburu/pgbouncer
|
||||||
|
container_name: pragativeer_pgbouncer
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgres://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod
|
||||||
|
volumes:
|
||||||
|
- ./pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
|
||||||
|
- ./userlist.txt:/etc/pgbouncer/userlist.txt:ro
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 5432 || exit 0"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- pragativeer_network
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 64m
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
container_name: pragativeer_prod_cache
|
container_name: pragativeer_cache
|
||||||
restart: unless-stopped
|
command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru --save ""
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- redisdata:/data
|
- redisdata:/data
|
||||||
networks:
|
networks:
|
||||||
- pragativeer_network
|
- pragativeer_network
|
||||||
healthcheck:
|
deploy:
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
resources:
|
||||||
interval: 5s
|
limits:
|
||||||
timeout: 5s
|
memory: 192m
|
||||||
retries: 12
|
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
# Tag the image so worker/beat can reuse it without rebuilding
|
||||||
|
image: pragativeer-backend:local
|
||||||
|
container_name: pragativeer_backend
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
- ./admin_uploads:/app/admin_uploads:ro
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@pgbouncer:5432/pragativeer_prod
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
- ENV=development
|
||||||
|
- MINIO_ENDPOINT=minio:9000
|
||||||
|
- MINIO_ACCESS_KEY=minio_admin
|
||||||
|
- MINIO_SECRET_KEY=minio_secure_password_2026
|
||||||
|
- MINIO_BUCKET=pragativeer-uploads
|
||||||
|
env_file:
|
||||||
|
- ./backend/.env
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
pgbouncer:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- pragativeer_network
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512m
|
||||||
|
|
||||||
|
worker:
|
||||||
|
# Reuse the image built by the 'backend' service — no separate build
|
||||||
|
image: pragativeer-backend:local
|
||||||
|
container_name: pragativeer_worker
|
||||||
|
command: celery -A worker.celery_app worker --loglevel=info --concurrency=2
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@pgbouncer:5432/pragativeer_prod
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
- MINIO_ENDPOINT=minio:9000
|
||||||
|
- MINIO_ACCESS_KEY=minio_admin
|
||||||
|
- MINIO_SECRET_KEY=minio_secure_password_2026
|
||||||
|
- MINIO_BUCKET=pragativeer-uploads
|
||||||
|
env_file:
|
||||||
|
- ./backend/.env
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- pragativeer_network
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256m
|
||||||
|
|
||||||
|
beat:
|
||||||
|
# Reuse the image built by the 'backend' service — no separate build
|
||||||
|
image: pragativeer-backend:local
|
||||||
|
container_name: pragativeer_beat
|
||||||
|
command: celery -A worker.celery_app beat --loglevel=info
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
environment:
|
||||||
|
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@pgbouncer:5432/pragativeer_prod
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
env_file:
|
||||||
|
- ./backend/.env
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
- postgres
|
||||||
|
- redis
|
||||||
|
networks:
|
||||||
|
- pragativeer_network
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128m
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- NEXT_PUBLIC_API_URL=http://backend:8000
|
||||||
|
container_name: pragativeer_frontend
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_API_URL=http://backend:8000
|
||||||
|
- NEXT_PUBLIC_PAYMENT_GATEWAY=razorpay
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
networks:
|
||||||
|
- pragativeer_network
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512m
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: minio/minio:latest
|
image: minio/minio:RELEASE.2024-06-13T22-53-53Z
|
||||||
container_name: pragativeer_prod_storage
|
container_name: pragativeer_storage
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
ports:
|
||||||
- "9025:9000"
|
- "9000:9000"
|
||||||
- "9026:9001"
|
- "9001:9001"
|
||||||
volumes:
|
volumes:
|
||||||
- miniodata:/data
|
- miniodata:/data
|
||||||
environment:
|
environment:
|
||||||
@@ -50,124 +185,10 @@ services:
|
|||||||
command: server /data --console-address ":9001"
|
command: server /data --console-address ":9001"
|
||||||
networks:
|
networks:
|
||||||
- pragativeer_network
|
- pragativeer_network
|
||||||
healthcheck:
|
deploy:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
resources:
|
||||||
interval: 5s
|
limits:
|
||||||
timeout: 5s
|
memory: 256m
|
||||||
retries: 12
|
|
||||||
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: ./backend
|
|
||||||
dockerfile: Dockerfile.prod
|
|
||||||
container_name: pragativeer_prod_backend
|
|
||||||
restart: unless-stopped
|
|
||||||
volumes:
|
|
||||||
- ./admin_uploads:/app/admin_uploads:ro
|
|
||||||
ports:
|
|
||||||
- "8010:8000"
|
|
||||||
environment:
|
|
||||||
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod
|
|
||||||
- REDIS_URL=redis://redis:6379/0
|
|
||||||
- ENV=production
|
|
||||||
- MINIO_ENDPOINT=minio:9000
|
|
||||||
- MINIO_ACCESS_KEY=minio_admin
|
|
||||||
- MINIO_SECRET_KEY=minio_secure_password_2026
|
|
||||||
- MINIO_BUCKET=pragativeer-uploads
|
|
||||||
- TZ=Asia/Kolkata
|
|
||||||
env_file:
|
|
||||||
- ./backend/.env
|
|
||||||
depends_on:
|
|
||||||
postgres:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
minio:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- pragativeer_network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 12
|
|
||||||
|
|
||||||
worker:
|
|
||||||
build:
|
|
||||||
context: ./backend
|
|
||||||
dockerfile: Dockerfile.prod
|
|
||||||
container_name: pragativeer_prod_worker
|
|
||||||
restart: unless-stopped
|
|
||||||
command: celery -A worker.celery_app worker --loglevel=info
|
|
||||||
environment:
|
|
||||||
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod
|
|
||||||
- REDIS_URL=redis://redis:6379/0
|
|
||||||
- MINIO_ENDPOINT=minio:9000
|
|
||||||
- MINIO_ACCESS_KEY=minio_admin
|
|
||||||
- MINIO_SECRET_KEY=minio_secure_password_2026
|
|
||||||
- MINIO_BUCKET=pragativeer-uploads
|
|
||||||
env_file:
|
|
||||||
- ./backend/.env
|
|
||||||
depends_on:
|
|
||||||
- postgres
|
|
||||||
- redis
|
|
||||||
networks:
|
|
||||||
- pragativeer_network
|
|
||||||
healthcheck:
|
|
||||||
# Celery worker serves no HTTP. Verify liveness via celery inspect ping.
|
|
||||||
# NOTE: output goes to a tmp file (not a pipe) — celery's forked children hold
|
|
||||||
# the pipe open and hang the check. Verified working in-container.
|
|
||||||
test: ["CMD-SHELL", "celery -A worker.celery_app inspect ping -d celery@$$HOSTNAME --timeout=5 > /tmp/hc.txt 2>&1; grep -q pong /tmp/hc.txt || exit 1"]
|
|
||||||
# Python cold-start makes the ping take 15-20s under load — generous timeout.
|
|
||||||
interval: 60s
|
|
||||||
timeout: 40s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
beat:
|
|
||||||
build:
|
|
||||||
context: ./backend
|
|
||||||
dockerfile: Dockerfile.prod
|
|
||||||
container_name: pragativeer_prod_beat
|
|
||||||
restart: unless-stopped
|
|
||||||
command: celery -A worker.celery_app beat --loglevel=info
|
|
||||||
environment:
|
|
||||||
- DATABASE_URL=postgresql://pragativeer_admin:local_secure_password_2026@postgres:5432/pragativeer_prod
|
|
||||||
- REDIS_URL=redis://redis:6379/0
|
|
||||||
env_file:
|
|
||||||
- ./backend/.env
|
|
||||||
depends_on:
|
|
||||||
- postgres
|
|
||||||
- redis
|
|
||||||
networks:
|
|
||||||
- pragativeer_network
|
|
||||||
healthcheck:
|
|
||||||
# Celery beat is a scheduler — no HTTP endpoint. pgrep isn't installed in the
|
|
||||||
# image; use a /proc scan instead. Verified working in-container.
|
|
||||||
test: ["CMD-SHELL", "grep -as 'celery.*[b]eat' /proc/*/cmdline > /dev/null 2>&1 || exit 1"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
args:
|
|
||||||
- NEXT_PUBLIC_API_URL=https://pragativeer.com
|
|
||||||
- BACKEND_INTERNAL_URL=http://backend:8000
|
|
||||||
container_name: pragativeer_prod_frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "3882:3000"
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
|
||||||
- BACKEND_INTERNAL_URL=http://backend:8000
|
|
||||||
- NEXT_PUBLIC_API_URL=https://pragativeer.com
|
|
||||||
- NEXT_PUBLIC_PAYMENT_GATEWAY=razorpay
|
|
||||||
depends_on:
|
|
||||||
- backend
|
|
||||||
networks:
|
|
||||||
- pragativeer_network
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
|
|||||||
@@ -11,6 +11,34 @@ const API_BASE =
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
|
|
||||||
|
// ── Performance: strip X-Powered-By header ──────────────────────────────
|
||||||
|
poweredByHeader: false,
|
||||||
|
|
||||||
|
// ── Performance: gzip compression handled by Next.js standalone server ──
|
||||||
|
compress: true,
|
||||||
|
|
||||||
|
// ── Compiler optimisations ───────────────────────────────────────────────
|
||||||
|
compiler: {
|
||||||
|
// Remove console.log statements from production builds
|
||||||
|
removeConsole: process.env.NODE_ENV === "production"
|
||||||
|
? { exclude: ["error", "warn"] }
|
||||||
|
: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── Tree-shake large packages (only import what is used) ─────────────────
|
||||||
|
// This tells Next.js to side-effect-free import specific packages,
|
||||||
|
// significantly reducing the bundle size for heavy libraries.
|
||||||
|
experimental: {
|
||||||
|
optimizePackageImports: [
|
||||||
|
"lucide-react",
|
||||||
|
"recharts",
|
||||||
|
"framer-motion",
|
||||||
|
"date-fns",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// ── API proxy rewrites ───────────────────────────────────────────────────
|
||||||
async rewrites() {
|
async rewrites() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user