diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f579ed5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,66 @@ +# Node modules +node_modules/ +dashboard/node_modules/ +backend/node_modules/ +demo/node_modules/ + +# Build outputs +dist/ +build/ +dashboard/dist/ + +# Environment files +.env +.env.local +.env.*.local +dashboard/.env +dashboard/.env.* + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Test +coverage/ +.nyc_output/ + +# Git +.git/ + +# Documentation +*.md +!README.md + +# Other workspaces +backend/ +demo/ +src/ +contracts/ +infra/ +tools/ +docs/ +.github/ +.kiro/ +AETHER_SOLUTIONS/ + +# Root dev artifacts +final_merge_log.txt +final_merge.py +robust_merge_log.txt +robust_merger.py +current_git_status.txt +requests_check.txt +open_prs.json +mutants.toml +prometheus.yml + +# Docker +docker-compose*.yml +Dockerfile +.dockerignore diff --git a/dashboard/.dockerignore b/dashboard/.dockerignore new file mode 100644 index 0000000..1821836 --- /dev/null +++ b/dashboard/.dockerignore @@ -0,0 +1,43 @@ +# Dependencies +node_modules +npm-debug.log + +# Build output +dist +build + +# Environment files +.env +.env.local +.env.*.local + +# IDE +.vscode +.idea +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Test +coverage +.nyc_output + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore +nginx.conf + +# Git +.git +.gitignore + +# Documentation +README.md + +# Logs +logs +*.log diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile new file mode 100644 index 0000000..8e8bed6 --- /dev/null +++ b/dashboard/Dockerfile @@ -0,0 +1,44 @@ +# Stage 1: Build the dashboard +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy root workspace files first for layer caching +COPY package.json package-lock.json ./ + +# Copy dashboard package.json +COPY dashboard/package.json ./dashboard/package.json + +# Install all workspace dependencies +RUN npm ci + +# Copy dashboard source code +COPY dashboard/ ./dashboard/ + +# Build the dashboard (TypeScript check + Vite build) +RUN npm run build -w dashboard + +# Stage 2: Serve with nginx +FROM nginx:alpine AS production + +# Remove default nginx static assets +RUN rm -rf /usr/share/nginx/html/* + +# Copy custom nginx configuration +COPY dashboard/nginx.conf /etc/nginx/conf.d/default.conf + +# Copy built static assets from builder stage +COPY --from=builder /app/dashboard/dist /usr/share/nginx/html + +# Expose port 80 +EXPOSE 80 + +# nginx runs as non-root by default in alpine; ensure proper permissions +RUN chown -R nginx:nginx /usr/share/nginx/html && \ + chmod -R 755 /usr/share/nginx/html + +# Health check via nginx process +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:80/ || exit 1 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/dashboard/nginx.conf b/dashboard/nginx.conf new file mode 100644 index 0000000..7a922c6 --- /dev/null +++ b/dashboard/nginx.conf @@ -0,0 +1,40 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Disable nginx version in error pages and headers + server_tokens off; + + # Gzip compression for text-based assets + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; + gzip_min_length 256; + gzip_vary on; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Cache immutable assets (hashed by Vite) + location ~* \.(?:css|js|woff2|woff|ttf|svg|png|jpg|jpeg|gif|ico|webp)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + # SPA fallback: all routes serve index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location = /health { + access_log off; + return 200 "OK"; + add_header Content-Type text/plain; + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 3b3dea3..f228226 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,28 @@ version: '3.8' services: + dashboard: + build: + context: . + dockerfile: dashboard/Dockerfile + container_name: anchorpoint-dashboard + ports: + - "3000:80" + environment: + - NODE_ENV=production + depends_on: + backend: + condition: service_healthy + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:80/health"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 5s + restart: unless-stopped + networks: + - anchorpoint-network + backend: build: context: ./backend