diff --git a/.dockerignore b/.dockerignore index dc10a51..200191e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,32 @@ -# Node artefacts -node_modules -npm-debug.log - -dist -data/* -*.env* +# never ship secrets .env +.env.* +*.env +**/*.env +**/*.env.* + +# VCS / workspace junk .git +.gitignore .vscode +.idea + +# node noise (server images install their own deps) +node_modules +**/node_modules +npm-debug.log* +yarn.lock +pnpm-lock.yaml + +# transient outputs (but KEEP build/ for nginx) +dist +coverage +.DS_Store +*.log + +# keys/certs +*.pem +*.key +*.crt +*.pfx + diff --git a/.woodpecker.yml b/.woodpecker.yml index c69badc..bc084b7 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -164,6 +164,7 @@ steps: when: event: - push + - manual branch: - master - dev-master diff --git a/Dockerfile.common b/Dockerfile.common deleted file mode 100644 index d4fe484..0000000 --- a/Dockerfile.common +++ /dev/null @@ -1,21 +0,0 @@ -# ---------- minimal Node runtime ---------- -FROM node:20-slim - -# 1. safe work dir -WORKDIR /app - -# 2. install prod deps only -COPY package*.json ./ -RUN apt-get update -y && apt-get install -y --no-install-recommends build-essential python3 make g++ && rm -rf /var/lib/apt/lists/* -RUN npm ci --omit=dev --ignore-scripts - -# 3. copy source -COPY . . - -# 4. expose port placeholder (overridden in child files) -ARG APPPORT=5000 -ENV PORT=$APPPORT -EXPOSE $APPPORT - -# 5. start -CMD ["npm","start"] diff --git a/Dockerfile.server1 b/Dockerfile.server1 index 4598767..c97bcf9 100644 --- a/Dockerfile.server1 +++ b/Dockerfile.server1 @@ -10,9 +10,13 @@ RUN apt-get update -y && \ rm -rf /var/lib/apt/lists/* COPY package*.json ./ -COPY public/ /app/public/ -RUN npm ci --unsafe-perm -COPY . . +RUN npm ci --unsafe-perm --omit=dev + +# app payload (only what runtime needs) +COPY --chown=app:app backend/ ./backend/ +COPY --chown=app:app src/ai/ ./src/ai/ +COPY --chown=app:app src/assets/ ./src/assets/ +COPY --chown=app:app public/ ./public/ RUN mkdir -p /run/secrets && chown -R app:app /run/secrets USER app diff --git a/Dockerfile.server2 b/Dockerfile.server2 index d1f7b03..838aaa5 100644 --- a/Dockerfile.server2 +++ b/Dockerfile.server2 @@ -10,9 +10,13 @@ RUN apt-get update -y && \ rm -rf /var/lib/apt/lists/* COPY package*.json ./ -COPY public/ /app/public/ -RUN npm ci --unsafe-perm -COPY . . +RUN npm ci --unsafe-perm --omit=dev + +# app payload (only what runtime needs) +COPY --chown=app:app backend/ ./backend/ +COPY --chown=app:app src/ai/ ./src/ai/ +COPY --chown=app:app src/assets/ ./src/assets/ +COPY --chown=app:app public/ ./public/ RUN mkdir -p /run/secrets && chown -R app:app /run/secrets USER app diff --git a/Dockerfile.server3 b/Dockerfile.server3 index 88723ed..30fc7b5 100644 --- a/Dockerfile.server3 +++ b/Dockerfile.server3 @@ -10,9 +10,13 @@ RUN apt-get update -y && \ rm -rf /var/lib/apt/lists/* COPY package*.json ./ -COPY public/ /app/public/ -RUN npm ci --unsafe-perm -COPY . . +RUN npm ci --unsafe-perm --omit=dev + +# app payload (only what runtime needs) +COPY --chown=app:app backend/ ./backend/ +COPY --chown=app:app src/ai/ ./src/ai/ +COPY --chown=app:app src/assets/ ./src/assets/ +COPY --chown=app:app public/ ./public/ RUN mkdir -p /run/secrets && chown -R app:app /run/secrets USER app diff --git a/backend/server3.js b/backend/server3.js index 4ec79f5..a9b6226 100644 --- a/backend/server3.js +++ b/backend/server3.js @@ -8,7 +8,8 @@ const __dirname = path.dirname(__filename); import express from 'express'; import helmet from 'helmet'; -import fs, { readFile } from 'fs/promises'; // <-- add this +import { readFile } from 'fs/promises'; // <-- add this +import fs from 'fs'; import multer from 'multer'; import fetch from 'node-fetch'; import mammoth from 'mammoth'; @@ -3876,7 +3877,22 @@ return res.json({ ------------------------------------------------------------------ */ // Setup file upload via multer -const upload = multer({ dest: 'uploads/' }); + // Writable data path (mounted at runtime) + const UPLOAD_DIR = process.env.UPLOAD_DIR || '/data/uploads'; + fs.mkdirSync(UPLOAD_DIR, { recursive: true }); // now valid + + const storage = multer.diskStorage({ + destination: (_req, _file, cb) => cb(null, UPLOAD_DIR), + filename: (_req, file, cb) => { + const base = path.basename(file.originalname).replace(/[^\w.\-]+/g, '_'); + cb(null, `${Date.now()}-${base}`); + } + }); + +const upload = multer({ + storage, + limits: { fileSize: 10 * 1024 * 1024 } // 10MB (tune as needed) +}); function buildResumePrompt(resumeText, jobTitle, jobDescription) { // Full ChatGPT prompt for resume optimization: diff --git a/docker-compose.yml b/docker-compose.yml index e0c992d..a5442ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -154,6 +154,7 @@ services: - ./salary_info.db:/app/salary_info.db:ro - ./user_profile.db:/app/user_profile.db - dek-vol:/run/secrets/dev:ro + - aptiva_uploads:/data/uploads healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost:${SERVER3_PORT}/livez || exit 1"] interval: 15s @@ -186,4 +187,5 @@ volumes: dek-vol: name: aptiva_dek_dev driver: local + aptiva_uploads: