From 012d849366573efa82fba64b1ffa962e091a0f01 Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sat, 28 Feb 2026 11:21:11 -0500 Subject: [PATCH] feat(infra): add Docker and nginx infrastructure for frontend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dev: Vite dev server in Node 24 container with hot reload via volume mount and named volume for node_modules isolation. Prod: Multi-stage build (pnpm build → nginx) serving static files with API/WebSocket reverse proxy to backend. --- .../advanced/ai-threat-detection/.env.example | 1 + .../advanced/ai-threat-detection/compose.yml | 21 ++++++++ .../ai-threat-detection/dev.compose.yml | 19 +++++++ .../frontend/vite.config.ts | 11 +++- .../ai-threat-detection/infra/docker/vite.dev | 18 +++++++ .../infra/docker/vite.prod | 29 +++++++++++ .../infra/nginx/vigil.conf | 52 +++++++++++++++++++ 7 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 PROJECTS/advanced/ai-threat-detection/infra/docker/vite.dev create mode 100644 PROJECTS/advanced/ai-threat-detection/infra/docker/vite.prod create mode 100644 PROJECTS/advanced/ai-threat-detection/infra/nginx/vigil.conf diff --git a/PROJECTS/advanced/ai-threat-detection/.env.example b/PROJECTS/advanced/ai-threat-detection/.env.example index 7ff83d4e..79e2ed40 100644 --- a/PROJECTS/advanced/ai-threat-detection/.env.example +++ b/PROJECTS/advanced/ai-threat-detection/.env.example @@ -13,6 +13,7 @@ API_KEY=changeme-generate-a-real-key POSTGRES_HOST_PORT=16969 REDIS_HOST_PORT=26969 BACKEND_HOST_PORT=36969 +FRONTEND_HOST_PORT=46969 # PostgreSQL POSTGRES_DB=angelusvigil diff --git a/PROJECTS/advanced/ai-threat-detection/compose.yml b/PROJECTS/advanced/ai-threat-detection/compose.yml index 49c8c5b0..d1818124 100644 --- a/PROJECTS/advanced/ai-threat-detection/compose.yml +++ b/PROJECTS/advanced/ai-threat-detection/compose.yml @@ -74,6 +74,27 @@ services: start_period: 10s restart: always + frontend: + build: + context: . + dockerfile: infra/docker/vite.prod + container_name: vigil-frontend + ports: + - "${FRONTEND_HOST_PORT:-80}:80" + depends_on: + backend: + condition: service_healthy + networks: + - vigil_network + - certgames_net + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + restart: always + geoip-updater: image: maxmindinc/geoipupdate:latest container_name: vigil-geoip diff --git a/PROJECTS/advanced/ai-threat-detection/dev.compose.yml b/PROJECTS/advanced/ai-threat-detection/dev.compose.yml index 5f3a12c7..93bfd664 100644 --- a/PROJECTS/advanced/ai-threat-detection/dev.compose.yml +++ b/PROJECTS/advanced/ai-threat-detection/dev.compose.yml @@ -71,6 +71,24 @@ services: retries: 3 start_period: 15s + frontend: + build: + context: . + dockerfile: infra/docker/vite.dev + container_name: vigil-frontend-dev + environment: + VITE_API_TARGET: http://backend:8000 + ports: + - "${FRONTEND_HOST_PORT:-46969}:5173" + volumes: + - ./frontend:/app + - frontend_node_modules_dev:/app/node_modules + depends_on: + backend: + condition: service_healthy + networks: + - vigil_dev + networks: vigil_dev: driver: bridge @@ -79,3 +97,4 @@ volumes: postgres_dev: redis_dev: nginx_logs_dev: + frontend_node_modules_dev: diff --git a/PROJECTS/advanced/ai-threat-detection/frontend/vite.config.ts b/PROJECTS/advanced/ai-threat-detection/frontend/vite.config.ts index a4ad5b31..41400a53 100644 --- a/PROJECTS/advanced/ai-threat-detection/frontend/vite.config.ts +++ b/PROJECTS/advanced/ai-threat-detection/frontend/vite.config.ts @@ -11,6 +11,10 @@ import tsconfigPaths from 'vite-tsconfig-paths' export default defineConfig(({ mode }) => { const env = loadEnv(mode, path.resolve(__dirname, '..'), '') const isDev = mode === 'development' + const apiTarget = + process.env.VITE_API_TARGET || + env.VITE_API_TARGET || + 'http://localhost:8000' return { plugins: [react(), tsconfigPaths()], @@ -32,10 +36,15 @@ export default defineConfig(({ mode }) => { host: '0.0.0.0', proxy: { '/api': { - target: env.VITE_API_TARGET || 'http://localhost:8000', + target: apiTarget, changeOrigin: true, rewrite: (p) => p.replace(/^\/api/, ''), }, + '/ws': { + target: apiTarget, + ws: true, + changeOrigin: true, + }, }, }, diff --git a/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.dev b/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.dev new file mode 100644 index 00000000..1a39298b --- /dev/null +++ b/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.dev @@ -0,0 +1,18 @@ +# ©AngelaMos | 2026 +# Development Vite Dockerfile +# Hot reload with volume mounts for source code + +FROM node:24-alpine + +RUN corepack enable && corepack prepare pnpm@latest --activate + +WORKDIR /app + +COPY frontend/package.json ./ +RUN pnpm install + +COPY frontend/ . + +EXPOSE 5173 + +CMD ["pnpm", "dev"] diff --git a/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.prod b/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.prod new file mode 100644 index 00000000..0400504b --- /dev/null +++ b/PROJECTS/advanced/ai-threat-detection/infra/docker/vite.prod @@ -0,0 +1,29 @@ +# ©AngelaMos | 2026 +# Production Vite Dockerfile +# Multi-stage build: pnpm build → nginx static serving + +FROM node:24-alpine AS builder + +RUN corepack enable && corepack prepare pnpm@latest --activate + +WORKDIR /app + +COPY frontend/package.json ./ +RUN pnpm install --frozen-lockfile + +COPY frontend/ . +RUN pnpm build + +FROM nginx:alpine + +RUN rm /etc/nginx/conf.d/default.conf + +COPY infra/nginx/vigil.conf /etc/nginx/conf.d/vigil.conf +COPY --from=builder /app/dist /usr/share/nginx/html + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \ + CMD wget -qO- http://localhost/health || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/PROJECTS/advanced/ai-threat-detection/infra/nginx/vigil.conf b/PROJECTS/advanced/ai-threat-detection/infra/nginx/vigil.conf new file mode 100644 index 00000000..f7f667f1 --- /dev/null +++ b/PROJECTS/advanced/ai-threat-detection/infra/nginx/vigil.conf @@ -0,0 +1,52 @@ +# ©AngelaMos | 2026 +# vigil.conf + +upstream vigil_backend { + server backend:8000; +} + +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml; + gzip_min_length 256; + + location / { + try_files $uri $uri/ /index.html; + } + + location /api/ { + proxy_pass http://vigil_backend/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 30s; + } + + location /ws/ { + proxy_pass http://vigil_backend/ws/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 86400s; + } + + location /health { + access_log off; + return 200 'ok'; + add_header Content-Type text/plain; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } +}