diff --git a/.gitignore b/.gitignore index 64db696..63e3afe 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,7 @@ helm/charts/ tmp/ temp/ *.tmp + +# Node.js +package-lock.json +**/package-lock.json diff --git a/Dockerfile b/Dockerfile index 66de827..b12df05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,30 @@ +# Multi-stage build: First stage builds Angular frontend +FROM node:24-alpine AS frontend-build + +# Accept npm registry as build argument +ARG NPM_REGISTRY=https://registry.npmjs.org/ + +WORKDIR /frontend + +# Copy package files +COPY frontend/package*.json ./ + +# Configure npm registry if custom registry is provided +RUN if [ "$NPM_REGISTRY" != "https://registry.npmjs.org/" ]; then \ + echo "Using custom npm registry: $NPM_REGISTRY"; \ + npm config set registry "$NPM_REGISTRY"; \ + fi + +# Install dependencies (ignore package-lock.json if using custom registry) +RUN npm install + +# Copy source code +COPY frontend/ ./ + +# Build for production +RUN npm run build:prod + +# Second stage: Python backend with Angular frontend FROM python:3.11-alpine WORKDIR /app @@ -20,7 +47,9 @@ COPY app/ ./app/ COPY utils/ ./utils/ COPY alembic/ ./alembic/ COPY alembic.ini . -COPY static/ ./static/ + +# Copy built Angular frontend from first stage to static directory +COPY --from=frontend-build /frontend/dist/frontend/browser ./static/ # Create non-root user (Alpine uses adduser instead of useradd) RUN adduser -D -u 1000 appuser && chown -R appuser:appuser /app diff --git a/Dockerfile.frontend b/Dockerfile.frontend deleted file mode 100644 index 21ad07e..0000000 --- a/Dockerfile.frontend +++ /dev/null @@ -1,40 +0,0 @@ -# Multi-stage build for Angular frontend -FROM node:24-alpine AS build - -# Accept npm registry as build argument -ARG NPM_REGISTRY=https://registry.npmjs.org/ - -WORKDIR /app - -# Copy package files -COPY frontend/package*.json ./ - -# Configure npm registry and regenerate package-lock.json if custom registry is provided -RUN if [ "$NPM_REGISTRY" != "https://registry.npmjs.org/" ]; then \ - echo "Using custom npm registry: $NPM_REGISTRY"; \ - npm config set registry "$NPM_REGISTRY"; \ - rm -f package-lock.json; \ - npm install --package-lock-only; \ - fi - -# Install dependencies -RUN npm ci - -# Copy source code -COPY frontend/ ./ - -# Build for production -RUN npm run build:prod - -# Final stage - nginx to serve static files -FROM nginx:alpine - -# Copy built Angular app to nginx -COPY --from=build /app/dist/frontend/browser /usr/share/nginx/html - -# Copy nginx configuration -COPY nginx.conf /etc/nginx/conf.d/default.conf - -EXPOSE 80 - -CMD ["nginx", "-g", "daemon off;"] diff --git a/Dockerfile.frontend.prebuilt b/Dockerfile.frontend.prebuilt deleted file mode 100644 index f5599ce..0000000 --- a/Dockerfile.frontend.prebuilt +++ /dev/null @@ -1,20 +0,0 @@ -# Dockerfile for pre-built Angular frontend (air-gapped/restricted environments) -# -# IMPORTANT: You must build the Angular app BEFORE running docker-compose! -# Run this command first: ./build-for-airgap.sh -# OR manually: cd frontend && npm install && npm run build:prod -# -# This Dockerfile expects frontend/dist/frontend/browser to exist - -FROM nginx:alpine - -# Copy pre-built Angular app to nginx -# If this step fails, you need to run: ./build-for-airgap.sh -COPY frontend/dist/frontend/browser /usr/share/nginx/html - -# Copy nginx configuration -COPY nginx.conf /etc/nginx/conf.d/default.conf - -EXPOSE 80 - -CMD ["nginx", "-g", "daemon off;"] diff --git a/app/main.py b/app/main.py index 6ac02e3..e6cd10a 100644 --- a/app/main.py +++ b/app/main.py @@ -84,6 +84,32 @@ async def ui_root(): } +# Catch-all route for Angular SPA routing - must be last +@app.get("/{full_path:path}") +async def serve_spa(full_path: str): + """Serve Angular SPA for all non-API routes""" + # If it's an API route, it should have been handled by routers above + # If it's a static file request, try to serve it + if full_path.startswith("static/"): + file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), full_path) + if os.path.exists(file_path): + return FileResponse(file_path) + + # For all other routes (Angular routes), serve index.html + index_path = os.path.join(static_dir, "index.html") + if os.path.exists(index_path): + return FileResponse(index_path) + else: + return { + "message": "Warehouse13 - Enterprise Test Artifact Storage", + "version": "1.0.0", + "docs": "/docs", + "ui": "UI not found. Serving API only.", + "deployment_mode": settings.deployment_mode, + "storage_backend": settings.storage_backend + } + + @app.get("/health") async def health_check(): """Health check endpoint""" diff --git a/build-for-airgap.sh b/build-for-airgap.sh deleted file mode 100755 index d91cf77..0000000 --- a/build-for-airgap.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -set -e - -echo "=========================================" -echo "Building Angular for Air-Gapped Deployment" -echo "=========================================" -echo "" - -# Check if we're in the right directory -if [ ! -f "docker-compose.yml" ]; then - echo "Error: Must run from project root directory" - exit 1 -fi - -# Check if node is installed -if ! command -v node &> /dev/null; then - echo "Error: Node.js is not installed. Please install Node.js 18+ first." - exit 1 -fi - -# Check if npm is installed -if ! command -v npm &> /dev/null; then - echo "Error: npm is not installed. Please install npm first." - exit 1 -fi - -echo "Step 1/3: Installing dependencies..." -cd frontend -npm install - -echo "" -echo "Step 2/3: Building Angular production bundle..." -npm run build:prod - -echo "" -echo "Step 3/3: Verifying build output..." -if [ -d "dist/frontend/browser" ]; then - echo "✓ Build successful!" - echo "✓ Output: frontend/dist/frontend/browser" - ls -lh dist/frontend/browser | head -5 -else - echo "✗ Build failed - output directory not found" - exit 1 -fi - -cd .. - -echo "" -echo "=========================================" -echo "Build Complete!" -echo "=========================================" -echo "" -echo "Next steps:" -echo "1. Update docker-compose.yml:" -echo " Change: dockerfile: Dockerfile.frontend" -echo " To: dockerfile: Dockerfile.frontend.prebuilt" -echo "" -echo "2. Deploy:" -echo " docker-compose up -d --build" -echo "" -echo "See DEPLOYMENT.md for more details." -echo "=========================================" diff --git a/docker-compose.yml b/docker-compose.yml index 8a2f2d1..d9bdac4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,20 +59,6 @@ services: timeout: 10s retries: 3 - frontend: - build: - context: . - dockerfile: Dockerfile.frontend.prebuilt - ports: - - "4200:80" - depends_on: - - api - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://localhost/"] - interval: 30s - timeout: 10s - retries: 3 - volumes: postgres_data: minio_data: diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index bcc9963..0000000 --- a/nginx.conf +++ /dev/null @@ -1,36 +0,0 @@ -server { - listen 80; - server_name localhost; - root /usr/share/nginx/html; - index index.html; - - # Gzip compression - gzip on; - gzip_vary on; - gzip_min_length 1024; - gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json; - - # Angular routes - serve index.html for all routes - location / { - try_files $uri $uri/ /index.html; - } - - # Proxy API requests to backend - location /api { - proxy_pass http://api:8000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - 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; - } - - # Cache static assets - location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { - expires 1y; - add_header Cache-Control "public, immutable"; - } -} diff --git a/quickstart-airgap.sh b/quickstart-airgap.sh index a726a32..4c6c03f 100755 --- a/quickstart-airgap.sh +++ b/quickstart-airgap.sh @@ -28,17 +28,12 @@ if ! command -v docker-compose &> /dev/null; then exit 1 fi -echo "Step 1: Building Angular frontend locally..." -echo "===========================================" -./build-for-airgap.sh - -echo "" -echo "Step 2: Starting Docker containers..." +echo "Step 1: Starting Docker containers..." echo "===========================================" docker-compose up -d --build echo "" -echo "Step 3: Waiting for services to be ready..." +echo "Step 2: Waiting for services to be ready..." sleep 15 echo "" @@ -46,8 +41,7 @@ echo "=========================================" echo "Services are running!" echo "=========================================" echo "" -echo "Frontend: http://localhost:4200" -echo "API: http://localhost:8000" +echo "Web UI: http://localhost:8000" echo "API Docs: http://localhost:8000/docs" echo "MinIO Console: http://localhost:9001" echo " Username: minioadmin" diff --git a/quickstart.sh b/quickstart.sh index 3bbafca..591d37c 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -41,7 +41,7 @@ echo "=========================================" echo "Services are running!" echo "=========================================" echo "" -echo "API: http://localhost:8000" +echo "Web UI: http://localhost:8000" echo "API Docs: http://localhost:8000/docs" echo "MinIO Console: http://localhost:9001" echo " Username: minioadmin"