From 1832f98d406e08b017ae46541e3b78ef98f9ac23 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Wed, 27 Aug 2025 17:37:22 -0500 Subject: [PATCH] changed docker --- Dockerfile | 49 +++++++++++++++++++++++++++++++++------------- docker-compose.yml | 32 +++++++++++++++++------------- package-lock.json | 31 +++++++++++++++++++++++++++-- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7ede900..79c2c17 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,40 +1,61 @@ -# Multi-stage build for production -FROM node:22-alpine AS deps +# ---------- Base for installs ---------- +FROM node:22-alpine AS base WORKDIR /app + +# ---------- Production deps ---------- +FROM base AS deps COPY package*.json ./ +# nur Prod-Deps für die runner-Stage (schnellerer Start, kleineres Image) RUN npm ci --only=production -FROM node:22-alpine AS builder -WORKDIR /app +# ---------- Full deps + Build ---------- +FROM base AS builder COPY package*.json ./ +# volle Deps inkl. devDependencies RUN npm ci +# Rest des Codes COPY . . RUN npm run build +# ---------- Development stage ---------- +FROM base AS dev +ENV NODE_ENV=development +# nur package-Dateien kopieren, damit npm install gecacht wird +COPY package*.json ./ +RUN npm install +# Quellcode kommt zur Laufzeit per Bind-Mount aus Compose +# (sorgt für Hot Reload) +EXPOSE 3000 +ENV HOSTNAME="0.0.0.0" +CMD ["npm", "run", "dev"] + +# ---------- Production runner ---------- FROM node:22-alpine AS runner WORKDIR /app ENV NODE_ENV=production ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" -# Create non-root user -RUN addgroup --system --gid 1001 nodejs -RUN adduser --system --uid 1001 nextjs +# non-root user +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs -# Copy built application +# für Healthcheck +RUN apk add --no-cache curl + +# statische Assets & Standalone-Output aus builder COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs - EXPOSE 3000 -ENV PORT=3000 -ENV HOSTNAME="0.0.0.0" - -# Health check +# Health check (pfad anpassen, falls dein Endpoint anders heißt) HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ - CMD curl -f http://localhost:3000/api/health || exit 1 + CMD curl -fsS http://127.0.0.1:3000/api/health || exit 1 +# Next.js standalone startet über server.js CMD ["node", "server.js"] + diff --git a/docker-compose.yml b/docker-compose.yml index 101b75a..8b1a520 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,38 +1,42 @@ -version: '3.8' - services: - # Development service + # ---- Development ---- app-dev: build: context: . dockerfile: Dockerfile + target: dev ports: - "3000:3000" - volumes: - - .:/app - - /app/node_modules - - /app/.next environment: - NODE_ENV=development - command: npm run dev - profiles: - - dev + - HOSTNAME=0.0.0.0 + # Hot-Reload & persistente Caches + volumes: + - .:/app + - node_modules:/app/node_modules + - next:/app/.next + # CMD kommt aus Dockerfile (npm run dev) + profiles: [dev] - # Production service + # ---- Production ---- app-prod: build: context: . dockerfile: Dockerfile + # target: runner # (optional; letzter Stage ist ohnehin runner) ports: - - "3000:3000" + - "3010:3000" environment: - NODE_ENV=production - SITE_URL=${SITE_URL:-https://hamtonbrown.com} - CONTACT_TO_EMAIL=${CONTACT_TO_EMAIL:-contact@hamtonbrown.com} - RESEND_API_KEY=${RESEND_API_KEY} restart: unless-stopped - profiles: - - prod + profiles: [prod] + +volumes: + node_modules: + next: networks: default: diff --git a/package-lock.json b/package-lock.json index d06ca60..f27e6de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,14 @@ { - "name": "hamtonbrown-cpa", + "name": "hamptonbrown-associates", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "hamtonbrown-cpa", + "name": "hamptonbrown-associates", "version": "0.1.0", "dependencies": { + "@hookform/resolvers": "^3.3.2", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", @@ -16,6 +17,7 @@ "next-sitemap": "^4.2.3", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-form": "^7.48.2", "resend": "^2.1.0", "tailwind-merge": "^2.0.0", "tailwindcss-animate": "^1.0.7", @@ -151,6 +153,15 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@hookform/resolvers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", + "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -5495,6 +5506,22 @@ "react": "^18.3.1" } }, + "node_modules/react-hook-form": { + "version": "7.62.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz", + "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/react-hook-form" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18 || ^19" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",