From 7bf73aa3746595c4feddcd85a66a32c86a1cc49f Mon Sep 17 00:00:00 2001 From: Justin McLellan Date: Tue, 24 Feb 2026 20:09:57 -0600 Subject: [PATCH] convert to container for migration --- Dockerfile | 13 --------- Dockerfile.migrations | 30 ++++++++++++++++++++ README.md | 64 +++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 24 +++++++++++----- 4 files changed, 111 insertions(+), 20 deletions(-) create mode 100644 Dockerfile.migrations diff --git a/Dockerfile b/Dockerfile index a073463..21de9de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,19 +60,6 @@ RUN apk add --no-cache wget COPY --from=builder --chown=nextjs:nodejs /app/public ./public 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/prisma ./prisma -COPY --from=builder --chown=nextjs:nodejs /app/prisma.config.ts ./prisma.config.ts -COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json -COPY --from=builder --chown=nextjs:nodejs /app/pnpm-lock.yaml ./pnpm-lock.yaml - -# Copy node_modules with Prisma from builder with correct ownership -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin/prisma ./node_modules/.bin/prisma -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.bin/tsx ./node_modules/.bin/tsx -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/.pnpm ./node_modules/.pnpm -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/prisma ./node_modules/prisma -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/@prisma ./node_modules/@prisma -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/dotenv ./node_modules/dotenv -COPY --from=builder --chown=nextjs:nodejs /app/node_modules/tsx ./node_modules/tsx USER nextjs diff --git a/Dockerfile.migrations b/Dockerfile.migrations new file mode 100644 index 0000000..cee6095 --- /dev/null +++ b/Dockerfile.migrations @@ -0,0 +1,30 @@ +# Dockerfile for running Prisma migrations +# This is a separate, lightweight container that runs migrations before the app starts + +FROM node:24-alpine + +# Enable corepack and prepare pnpm +RUN corepack enable && corepack prepare pnpm@latest --activate + +WORKDIR /app + +# Create nextjs user for consistency +RUN addgroup --system --gid 1001 nodejs && \ + adduser --system --uid 1001 nextjs + +# Copy only files needed for migrations +COPY --chown=nextjs:nodejs package.json pnpm-lock.yaml ./ +COPY --chown=nextjs:nodejs prisma ./prisma +COPY --chown=nextjs:nodejs prisma.config.ts ./prisma.config.ts + +# Install production dependencies (skip postinstall to avoid prisma generate before CLI is available) +# Then install prisma CLI from devDependencies and generate client +RUN pnpm install --frozen-lockfile --prod --ignore-scripts && \ + pnpm add -D prisma && \ + pnpm exec prisma generate + +# Switch to non-root user +USER nextjs + +# Run migrations +CMD ["pnpm", "prisma", "migrate", "deploy"] diff --git a/README.md b/README.md index d0d32f9..c7784f7 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,67 @@ This project uses [`next/font`](https://nextjs.org/docs/app/building-your-applic - [Resend](https://resend.com) - emails If you want to contribute to this template for future projects please work with the teaching staff. We welcome any technologies that could benefit the partners and speed to delivery for features. + +## Production Deployment + +The application uses Docker Compose for production deployments with an automated migration workflow: + +### Architecture + +- **Database**: PostgreSQL 17 with persistent volume storage +- **Migrations**: Separate init container that runs database migrations before the app starts +- **Application**: Next.js standalone server with optimized production build + +### Deployment Commands + +Build and start all services: + +```bash +docker compose --profile production up -d --build +``` + +Check service status: + +```bash +docker compose ps +``` + +View logs: + +```bash +# All services +docker compose logs + +# Specific service +docker compose logs template-app +docker compose logs template-migrations +``` + +Stop services: + +```bash +docker compose --profile production down +``` + +Clean shutdown with volume and orphan container removal: + +```bash +docker compose --profile production down --volumes --remove-orphans +``` + +### Migration Workflow + +1. **Database starts** and waits for healthy status +2. **Migration container** runs `prisma migrate deploy` and exits +3. **Application starts** only after migrations complete successfully + +The migration container (`template-migrations`) runs once per deployment and automatically exits after completion. Docker Compose handles cleanup of stopped containers on subsequent deployments. + +### Environment Variables + +All required environment variables must be set in your `.env` file before deployment. See `example.env` for the complete list. Key variables: + +- `DATABASE_*`: PostgreSQL connection settings +- `AUTH_*`: NextAuth configuration +- `NEXT_PUBLIC_VAPID_PUBLIC_KEY` / `VAPID_PRIVATE_KEY`: Push notification keys +- `RESEND_API_KEY`: Email service configuration diff --git a/docker-compose.yml b/docker-compose.yml index 13770bb..9c9a280 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,20 @@ services: timeout: 5s retries: 5 + # Database migrations (production only) + template-migrations: + build: + context: . + dockerfile: Dockerfile.migrations + environment: + - DATABASE_URL=postgresql://${DATABASE_USER}:${DATABASE_PW}@template-db:5432/${DATABASE_NAME} + restart: "no" + depends_on: + template-db: + condition: service_healthy + profiles: + - production + # Next.js application (production only) template-app: build: @@ -40,16 +54,12 @@ services: - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY} - NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000} - AUTH_TRUST_HOST=${AUTH_TRUST_HOST:-true} - command: > - sh -c " - echo 'Running database migrations...' && - ./node_modules/.bin/prisma migrate deploy && - echo 'Migrations completed, starting application...' && - node server.js - " + command: node server.js depends_on: template-db: condition: service_healthy + template-migrations: + condition: service_completed_successfully healthcheck: test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1"] interval: 10s