From a328da679c0a7b2d5b64e8203069c35f9391ac4f Mon Sep 17 00:00:00 2001 From: chamikaJ Date: Fri, 25 Apr 2025 12:30:15 +0530 Subject: [PATCH 1/9] Update docker-compose.yml to use bind mount for database initialization and add script execution for dos2unix; modify CORS origin check in app.ts for production environment --- docker-compose.yml | 18 +++++++++++++++++- worklenz-backend/src/app.ts | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 02dab3ee..c80eb976 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -113,7 +113,23 @@ services: - worklenz volumes: - worklenz_postgres_data:/var/lib/postgresql/data - - ./worklenz-backend/database/:/docker-entrypoint-initdb.d + - type: bind + source: ./worklenz-backend/database + target: /docker-entrypoint-initdb.d + consistency: cached + command: > + bash -c ' + if command -v apt-get >/dev/null 2>&1; then + apt-get update && apt-get install -y dos2unix + elif command -v apk >/dev/null 2>&1; then + apk add --no-cache dos2unix + fi && + find /docker-entrypoint-initdb.d -type f -name "*.sh" -exec sh -c '\'' + dos2unix "{}" 2>/dev/null || true + chmod +x "{}" + '\'' \; && + exec docker-entrypoint.sh postgres + ' volumes: worklenz_postgres_data: diff --git a/worklenz-backend/src/app.ts b/worklenz-backend/src/app.ts index 4fead2d9..28ed9095 100644 --- a/worklenz-backend/src/app.ts +++ b/worklenz-backend/src/app.ts @@ -69,7 +69,7 @@ const allowedOrigins = [ app.use(cors({ origin: (origin, callback) => { - if (!origin || allowedOrigins.includes(origin)) { + if (!isProduction() || !origin || allowedOrigins.includes(origin)) { callback(null, true); } else { console.log("Blocked origin:", origin, process.env.NODE_ENV); From 9c27c41a5eefc44a6385c501ad94d445d3f4ec54 Mon Sep 17 00:00:00 2001 From: chamikaJ Date: Fri, 25 Apr 2025 16:42:45 +0530 Subject: [PATCH 2/9] Add script to inject environment variables in Dockerfile - Created a start.sh script to set environment variables for the application. - Updated CMD to execute the new script instead of directly serving the build. --- worklenz-frontend/Dockerfile | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/worklenz-frontend/Dockerfile b/worklenz-frontend/Dockerfile index ac1f820f..5b1c338d 100644 --- a/worklenz-frontend/Dockerfile +++ b/worklenz-frontend/Dockerfile @@ -16,5 +16,16 @@ WORKDIR /app RUN npm install -g serve COPY --from=build /app/build /app/build + +# Create a script to inject environment variables +RUN echo '#!/bin/sh\n\ +cat > /app/build/env.js << EOL\n\ +window.env = {\n\ + VITE_API_URL: "${VITE_API_URL}"\n\ +};\n\ +EOL\n\ +exec serve -s build -l 5000' > /app/start.sh && \ +chmod +x /app/start.sh + EXPOSE 5000 -CMD ["serve", "-s", "build", "-l", "5000"] \ No newline at end of file +CMD ["/app/start.sh"] \ No newline at end of file From 2a3ae31e4e4a0bc7b0a29ff542169b7337377530 Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 11:32:44 +0530 Subject: [PATCH 3/9] Enhance Docker deployment with environment variable configuration - Added environment variable setup in docker-compose.yml for VITE_API_URL. - Introduced update-docker-env.sh script to create/update .env file for local and remote deployments. - Updated Dockerfile to dynamically create env-config.js during build. - Modified frontend to load environment configuration from env-config.js. - Refactored API client to use centralized config for API URL. --- README.md | 55 +++++++++++++++++++ docker-compose.yml | 2 + update-docker-env.sh | 34 ++++++++++++ worklenz-frontend/Dockerfile | 14 +++-- worklenz-frontend/index.html | 2 + worklenz-frontend/src/api/api-client.ts | 5 +- .../api/home-page/home-page.api.service.ts | 3 +- .../api/projects/projects.v1.api.service.ts | 3 +- worklenz-frontend/src/config/env.ts | 31 +++++++++++ 9 files changed, 140 insertions(+), 9 deletions(-) create mode 100755 update-docker-env.sh create mode 100644 worklenz-frontend/src/config/env.ts diff --git a/README.md b/README.md index 92ed1a90..2fe34797 100644 --- a/README.md +++ b/README.md @@ -389,3 +389,58 @@ For MinIO in production, consider: - Setting up proper networking and access controls - Using multiple MinIO instances for high availability +## Docker Deployment + +### Local Development with Docker + +1. Set up the environment variables: + ```bash + ./update-docker-env.sh + ``` + + This will create a `.env` file with default settings for local development. + +2. Run the application using Docker Compose: + ```bash + docker-compose up -d + ``` + +3. Access the application: + - Frontend: http://localhost:5000 + - Backend API: http://localhost:3000 + +### Remote Server Deployment + +When deploying to a remote server: + +1. Set up the environment variables with your server's hostname: + ```bash + ./update-docker-env.sh your-server-hostname + ``` + + This ensures that the frontend correctly connects to the backend API. + +2. Pull and run the latest Docker images: + ```bash + docker-compose pull + docker-compose up -d + ``` + +3. Access the application through your server's hostname: + - Frontend: http://your-server-hostname:5000 + - Backend API: http://your-server-hostname:3000 + +### Environment Configuration + +The Docker setup uses environment variables to configure the services: + +- Frontend: + - `VITE_API_URL`: URL of the backend API (default: http://backend:3000 for container networking) + +- Backend: + - Database connection parameters + - Storage configuration + - Other backend settings + +For custom configuration, edit the `.env` file or the `update-docker-env.sh` script. + diff --git a/docker-compose.yml b/docker-compose.yml index c80eb976..30e9c058 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,8 @@ services: depends_on: backend: condition: service_started + environment: + - VITE_API_URL=${VITE_API_URL:-http://backend:3000} networks: - worklenz diff --git a/update-docker-env.sh b/update-docker-env.sh new file mode 100755 index 00000000..5a7fc614 --- /dev/null +++ b/update-docker-env.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Script to set environment variables for Docker deployment +# Usage: ./update-docker-env.sh [hostname] + +# Default hostname if not provided +DEFAULT_HOSTNAME="localhost" +HOSTNAME=${1:-$DEFAULT_HOSTNAME} + +# Create or update root .env file +cat > .env << EOL +# Frontend Configuration +VITE_API_URL=http://${HOSTNAME}:3000 + +# Backend Configuration +DB_HOST=db +DB_PORT=5432 +DB_USER=postgres +DB_PASSWORD=password +DB_NAME=worklenz_db +NODE_ENV=development +PORT=3000 + +# Storage Configuration +AWS_REGION=us-east-1 +STORAGE_PROVIDER=s3 +BUCKET=worklenz-bucket +S3_ACCESS_KEY_ID=minioadmin +S3_SECRET_ACCESS_KEY=minioadmin +S3_URL=http://minio:9000 +EOL + +echo "Environment configuration updated for ${HOSTNAME}" +echo "To run with Docker Compose, use: docker-compose up -d" \ No newline at end of file diff --git a/worklenz-frontend/Dockerfile b/worklenz-frontend/Dockerfile index 5b1c338d..512ec923 100644 --- a/worklenz-frontend/Dockerfile +++ b/worklenz-frontend/Dockerfile @@ -7,6 +7,10 @@ COPY package.json package-lock.json ./ RUN npm ci COPY . . + +# Create env-config.js dynamically during build +RUN echo "window.VITE_API_URL='${VITE_API_URL:-http://backend:3000}';" > ./public/env-config.js + RUN npm run build FROM node:22-alpine AS production @@ -16,13 +20,13 @@ WORKDIR /app RUN npm install -g serve COPY --from=build /app/build /app/build +COPY --from=build /app/public/env-config.js /app/build/env-config.js -# Create a script to inject environment variables +# Create a script to start server and dynamically update env-config.js RUN echo '#!/bin/sh\n\ -cat > /app/build/env.js << EOL\n\ -window.env = {\n\ - VITE_API_URL: "${VITE_API_URL}"\n\ -};\n\ +# Update env-config.js with runtime environment variables\n\ +cat > /app/build/env-config.js << EOL\n\ +window.VITE_API_URL="${VITE_API_URL:-http://backend:3000}";\n\ EOL\n\ exec serve -s build -l 5000' > /app/start.sh && \ chmod +x /app/start.sh diff --git a/worklenz-frontend/index.html b/worklenz-frontend/index.html index bad8d4a3..86abad6e 100644 --- a/worklenz-frontend/index.html +++ b/worklenz-frontend/index.html @@ -12,6 +12,8 @@ rel="stylesheet" /> Worklenz + + diff --git a/worklenz-frontend/src/api/api-client.ts b/worklenz-frontend/src/api/api-client.ts index e87e0b61..ec43f7a5 100644 --- a/worklenz-frontend/src/api/api-client.ts +++ b/worklenz-frontend/src/api/api-client.ts @@ -2,6 +2,7 @@ import axios, { AxiosError } from 'axios'; import alertService from '@/services/alerts/alertService'; import logger from '@/utils/errorLogger'; +import config from '@/config/env'; export const getCsrfToken = (): string | null => { const match = document.cookie.split('; ').find(cookie => cookie.startsWith('XSRF-TOKEN=')); @@ -16,7 +17,7 @@ export const getCsrfToken = (): string | null => { export const refreshCsrfToken = async (): Promise => { try { // Make a GET request to the server to get a fresh CSRF token - await axios.get(`${import.meta.env.VITE_API_URL}/csrf-token`, { withCredentials: true }); + await axios.get(`${config.apiUrl}/csrf-token`, { withCredentials: true }); return getCsrfToken(); } catch (error) { console.error('Failed to refresh CSRF token:', error); @@ -25,7 +26,7 @@ export const refreshCsrfToken = async (): Promise => { }; const apiClient = axios.create({ - baseURL: import.meta.env.VITE_API_URL, + baseURL: config.apiUrl, withCredentials: true, headers: { 'Content-Type': 'application/json', diff --git a/worklenz-frontend/src/api/home-page/home-page.api.service.ts b/worklenz-frontend/src/api/home-page/home-page.api.service.ts index de83bd70..74f5615a 100644 --- a/worklenz-frontend/src/api/home-page/home-page.api.service.ts +++ b/worklenz-frontend/src/api/home-page/home-page.api.service.ts @@ -6,13 +6,14 @@ import { IHomeTasksModel, IHomeTasksConfig } from '@/types/home/home-page.types' import { IMyTask } from '@/types/home/my-tasks.types'; import { IProject } from '@/types/project/project.types'; import { getCsrfToken } from '../api-client'; +import config from '@/config/env'; const rootUrl = '/home'; const api = createApi({ reducerPath: 'homePageApi', baseQuery: fetchBaseQuery({ - baseUrl: `${import.meta.env.VITE_API_URL}${API_BASE_URL}`, + baseUrl: `${config.apiUrl}${API_BASE_URL}`, prepareHeaders: headers => { headers.set('X-CSRF-Token', getCsrfToken() || ''); headers.set('Content-Type', 'application/json'); diff --git a/worklenz-frontend/src/api/projects/projects.v1.api.service.ts b/worklenz-frontend/src/api/projects/projects.v1.api.service.ts index 8e6be422..1fe279d5 100644 --- a/worklenz-frontend/src/api/projects/projects.v1.api.service.ts +++ b/worklenz-frontend/src/api/projects/projects.v1.api.service.ts @@ -6,13 +6,14 @@ import { IProjectsViewModel } from '@/types/project/projectsViewModel.types'; import { IServerResponse } from '@/types/common.types'; import { IProjectMembersViewModel } from '@/types/projectMember.types'; import { getCsrfToken } from '../api-client'; +import config from '@/config/env'; const rootUrl = '/projects'; export const projectsApi = createApi({ reducerPath: 'projectsApi', baseQuery: fetchBaseQuery({ - baseUrl: `${import.meta.env.VITE_API_URL}${API_BASE_URL}`, + baseUrl: `${config.apiUrl}${API_BASE_URL}`, prepareHeaders: headers => { headers.set('X-CSRF-Token', getCsrfToken() || ''); headers.set('Content-Type', 'application/json'); diff --git a/worklenz-frontend/src/config/env.ts b/worklenz-frontend/src/config/env.ts new file mode 100644 index 00000000..10433940 --- /dev/null +++ b/worklenz-frontend/src/config/env.ts @@ -0,0 +1,31 @@ +/** + * Environment configuration + * Reads from window.VITE_API_URL (set by env-config.js) + * Falls back to import.meta.env.VITE_API_URL (set during build time) + * Falls back to a development default + */ + +declare global { + interface Window { + VITE_API_URL?: string; + } +} + +export const getApiUrl = (): string => { + // First check runtime-injected environment variables + if (window.VITE_API_URL) { + return window.VITE_API_URL; + } + + // Then check build-time environment variables + if (import.meta.env.VITE_API_URL) { + return import.meta.env.VITE_API_URL; + } + + // Default for development + return 'http://localhost:3000'; +}; + +export default { + apiUrl: getApiUrl(), +}; \ No newline at end of file From 6e4bdea1c2b32b85fb71e52bea51ef544bdce8ab Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 11:43:16 +0530 Subject: [PATCH 4/9] Enhance WebSocket support and update environment configuration - Added VITE_SOCKET_URL to docker-compose.yml for WebSocket connection. - Updated update-docker-env.sh to handle SSL options for WebSocket URLs. - Modified Dockerfile to include VITE_SOCKET_URL in env-config.js. - Implemented getSocketUrl function in frontend to retrieve WebSocket URL. - Refactored socket configuration to use centralized socket URL from environment settings. --- README.md | 11 ++++++++- docker-compose.yml | 1 + update-docker-env.sh | 24 ++++++++++++++++---- worklenz-frontend/Dockerfile | 4 +++- worklenz-frontend/src/config/env.ts | 31 +++++++++++++++++++++++--- worklenz-frontend/src/socket/config.ts | 4 +++- 6 files changed, 65 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2fe34797..db71d6f9 100644 --- a/README.md +++ b/README.md @@ -395,7 +395,11 @@ For MinIO in production, consider: 1. Set up the environment variables: ```bash + # For HTTP/WS ./update-docker-env.sh + + # For HTTPS/WSS + ./update-docker-env.sh localhost true ``` This will create a `.env` file with default settings for local development. @@ -407,7 +411,7 @@ For MinIO in production, consider: 3. Access the application: - Frontend: http://localhost:5000 - - Backend API: http://localhost:3000 + - Backend API: http://localhost:3000 (or https://localhost:3000 with SSL) ### Remote Server Deployment @@ -415,7 +419,11 @@ When deploying to a remote server: 1. Set up the environment variables with your server's hostname: ```bash + # For HTTP/WS ./update-docker-env.sh your-server-hostname + + # For HTTPS/WSS + ./update-docker-env.sh your-server-hostname true ``` This ensures that the frontend correctly connects to the backend API. @@ -436,6 +444,7 @@ The Docker setup uses environment variables to configure the services: - Frontend: - `VITE_API_URL`: URL of the backend API (default: http://backend:3000 for container networking) + - `VITE_SOCKET_URL`: WebSocket URL for real-time communication (default: ws://backend:3000) - Backend: - Database connection parameters diff --git a/docker-compose.yml b/docker-compose.yml index 30e9c058..8c6a831e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,6 +9,7 @@ services: condition: service_started environment: - VITE_API_URL=${VITE_API_URL:-http://backend:3000} + - VITE_SOCKET_URL=${VITE_SOCKET_URL:-ws://backend:3000} networks: - worklenz diff --git a/update-docker-env.sh b/update-docker-env.sh index 5a7fc614..1ba25997 100755 --- a/update-docker-env.sh +++ b/update-docker-env.sh @@ -1,16 +1,29 @@ #!/bin/bash # Script to set environment variables for Docker deployment -# Usage: ./update-docker-env.sh [hostname] +# Usage: ./update-docker-env.sh [hostname] [use_ssl] # Default hostname if not provided DEFAULT_HOSTNAME="localhost" HOSTNAME=${1:-$DEFAULT_HOSTNAME} +# Check if SSL should be used +USE_SSL=${2:-false} + +# Set protocol prefixes based on SSL flag +if [ "$USE_SSL" = "true" ]; then + HTTP_PREFIX="https://" + WS_PREFIX="wss://" +else + HTTP_PREFIX="http://" + WS_PREFIX="ws://" +fi + # Create or update root .env file cat > .env << EOL # Frontend Configuration -VITE_API_URL=http://${HOSTNAME}:3000 +VITE_API_URL=${HTTP_PREFIX}${HOSTNAME}:3000 +VITE_SOCKET_URL=${WS_PREFIX}${HOSTNAME}:3000 # Backend Configuration DB_HOST=db @@ -30,5 +43,8 @@ S3_SECRET_ACCESS_KEY=minioadmin S3_URL=http://minio:9000 EOL -echo "Environment configuration updated for ${HOSTNAME}" -echo "To run with Docker Compose, use: docker-compose up -d" \ No newline at end of file +echo "Environment configuration updated for ${HOSTNAME} with" $([ "$USE_SSL" = "true" ] && echo "HTTPS/WSS" || echo "HTTP/WS") +echo "To run with Docker Compose, use: docker-compose up -d" +echo +echo "API URL: ${VITE_API_URL:-${HTTP_PREFIX}${HOSTNAME}:3000}" +echo "Socket URL: ${VITE_SOCKET_URL:-${WS_PREFIX}${HOSTNAME}:3000}" \ No newline at end of file diff --git a/worklenz-frontend/Dockerfile b/worklenz-frontend/Dockerfile index 512ec923..f1e98751 100644 --- a/worklenz-frontend/Dockerfile +++ b/worklenz-frontend/Dockerfile @@ -9,7 +9,8 @@ RUN npm ci COPY . . # Create env-config.js dynamically during build -RUN echo "window.VITE_API_URL='${VITE_API_URL:-http://backend:3000}';" > ./public/env-config.js +RUN echo "window.VITE_API_URL='${VITE_API_URL:-http://backend:3000}';" > ./public/env-config.js && \ + echo "window.VITE_SOCKET_URL='${VITE_SOCKET_URL:-ws://backend:3000}';" >> ./public/env-config.js RUN npm run build @@ -27,6 +28,7 @@ RUN echo '#!/bin/sh\n\ # Update env-config.js with runtime environment variables\n\ cat > /app/build/env-config.js << EOL\n\ window.VITE_API_URL="${VITE_API_URL:-http://backend:3000}";\n\ +window.VITE_SOCKET_URL="${VITE_SOCKET_URL:-ws://backend:3000}";\n\ EOL\n\ exec serve -s build -l 5000' > /app/start.sh && \ chmod +x /app/start.sh diff --git a/worklenz-frontend/src/config/env.ts b/worklenz-frontend/src/config/env.ts index 10433940..948a0c70 100644 --- a/worklenz-frontend/src/config/env.ts +++ b/worklenz-frontend/src/config/env.ts @@ -1,13 +1,14 @@ /** * Environment configuration - * Reads from window.VITE_API_URL (set by env-config.js) - * Falls back to import.meta.env.VITE_API_URL (set during build time) - * Falls back to a development default + * Reads from window environment variables (set by env-config.js) + * Falls back to import.meta.env variables (set during build time) + * Falls back to development defaults */ declare global { interface Window { VITE_API_URL?: string; + VITE_SOCKET_URL?: string; } } @@ -26,6 +27,30 @@ export const getApiUrl = (): string => { return 'http://localhost:3000'; }; +export const getSocketUrl = (): string => { + // First check runtime-injected environment variables + if (window.VITE_SOCKET_URL) { + return window.VITE_SOCKET_URL; + } + + // Then check build-time environment variables + if (import.meta.env.VITE_SOCKET_URL) { + return import.meta.env.VITE_SOCKET_URL; + } + + // Default based on API URL (convert http->ws or https->wss) + const apiUrl = getApiUrl(); + if (apiUrl.startsWith('https://')) { + return apiUrl.replace('https://', 'wss://'); + } else if (apiUrl.startsWith('http://')) { + return apiUrl.replace('http://', 'ws://'); + } + + // Final fallback + return 'ws://localhost:3000'; +}; + export default { apiUrl: getApiUrl(), + socketUrl: getSocketUrl(), }; \ No newline at end of file diff --git a/worklenz-frontend/src/socket/config.ts b/worklenz-frontend/src/socket/config.ts index 867330c7..56049e85 100644 --- a/worklenz-frontend/src/socket/config.ts +++ b/worklenz-frontend/src/socket/config.ts @@ -1,5 +1,7 @@ +import config from '@/config/env'; + export const SOCKET_CONFIG = { - url: import.meta.env.VITE_SOCKET_URL || 'ws://localhost:3000', + url: config.socketUrl, options: { transports: ['websocket'], path: '/socket', From ac2afd694937bb56e9724543bf35b285a76ca9cc Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 12:37:41 +0530 Subject: [PATCH 5/9] Remove legacy environment files and update Docker configuration for environment management - Deleted .env and .env.example files to streamline environment variable management. - Updated docker-compose.yml to utilize env_file for frontend and backend services. - Enhanced update-docker-env.sh to create separate environment files for development and production. - Revised README.md to reflect the new environment file structure and setup instructions. --- .env | 34 ------------ .env.example | 34 ------------ README.md | 52 +++++++----------- docker-compose.yml | 37 ++----------- update-docker-env.sh | 100 ++++++++++++++++++++++++++++++---- worklenz-backend/.env.example | 76 -------------------------- 6 files changed, 113 insertions(+), 220 deletions(-) delete mode 100644 .env delete mode 100644 .env.example delete mode 100644 worklenz-backend/.env.example diff --git a/.env b/.env deleted file mode 100644 index 97d22a55..00000000 --- a/.env +++ /dev/null @@ -1,34 +0,0 @@ -# Database configuration -DB_USER=postgres -DB_PASSWORD=password -DB_NAME=worklenz_db -DB_HOST=db -DB_PORT=5432 -DB_MAX_CLIENTS=50 - -# Server configuration -NODE_ENV=development -PORT=3000 -SESSION_NAME=worklenz.sid -SESSION_SECRET=worklenz-session-secret -COOKIE_SECRET=worklenz-cookie-secret - -# CORS -SOCKET_IO_CORS=http://localhost:5000 -SERVER_CORS=* - -# Storage configuration (MinIO) -STORAGE_PROVIDER=s3 -AWS_REGION=us-east-1 -AWS_BUCKET=worklenz-bucket -S3_ACCESS_KEY_ID=minioadmin -S3_SECRET_ACCESS_KEY=minioadmin -S3_URL=http://minio:9000 - -# Application URLs -HOSTNAME=localhost:5000 -FRONTEND_URL=http://localhost:5000 - -# For local development, set these to the frontend service -LOGIN_FAILURE_REDIRECT=http://localhost:5000 -LOGIN_SUCCESS_REDIRECT=http://localhost:5000/auth/authenticate \ No newline at end of file diff --git a/.env.example b/.env.example deleted file mode 100644 index 9765d3cc..00000000 --- a/.env.example +++ /dev/null @@ -1,34 +0,0 @@ -# Database configuration -DB_USER=postgres -DB_PASSWORD=your_db_password -DB_NAME=worklenz_db -DB_HOST=localhost -DB_PORT=5432 -DB_MAX_CLIENTS=50 - -# Server configuration -NODE_ENV=development -PORT=3000 -SESSION_NAME=worklenz.sid -SESSION_SECRET=your_session_secret -COOKIE_SECRET=your_cookie_secret - -# CORS -SOCKET_IO_CORS=http://localhost:5000 -SERVER_CORS=* - -# Storage configuration -STORAGE_PROVIDER=s3 -AWS_REGION=your_aws_region -AWS_BUCKET=your_bucket_name -S3_ACCESS_KEY_ID=your_access_key_id -S3_SECRET_ACCESS_KEY=your_secret_access_key -S3_URL=your_s3_url - -# Application URLs -HOSTNAME=localhost:5000 -FRONTEND_URL=http://localhost:5000 - -# For local development -LOGIN_FAILURE_REDIRECT=http://localhost:5000 -LOGIN_SUCCESS_REDIRECT=http://localhost:5000/auth/authenticate \ No newline at end of file diff --git a/README.md b/README.md index db71d6f9..a6885d95 100644 --- a/README.md +++ b/README.md @@ -358,42 +358,34 @@ const s3Client = new S3Client({ ### Environment Configuration -The `.env` file includes the necessary configuration for using MinIO: +The project uses the following environment file structure: -``` -STORAGE_PROVIDER=s3 -AWS_REGION=us-east-1 -AWS_BUCKET=worklenz-bucket -S3_ACCESS_KEY_ID=minioadmin -S3_SECRET_ACCESS_KEY=minioadmin -S3_URL=http://minio:9000 +- **Frontend**: + - `worklenz-frontend/.env.development` - Development environment variables + - `worklenz-frontend/.env.production` - Production build variables + +- **Backend**: + - `worklenz-backend/.env` - Backend environment variables + +### Setting Up Environment Files + +The Docker environment script will create or overwrite all environment files: + +```bash +# For HTTP/WS +./update-docker-env.sh your-hostname + +# For HTTPS/WSS +./update-docker-env.sh your-hostname true ``` -When the backend service starts, it will use these environment variables to connect to MinIO for file storage. - -## Development - -For development, you can use the provided Docker setup which includes all necessary dependencies. The code will be running inside containers, but you can still edit files locally and see changes reflected in real-time. - -## Production Deployment - -For production deployment: - -1. Update the `.env` file with production settings -2. Build custom Docker images or use the provided ones -3. Deploy using Docker Compose or a container orchestration platform like Kubernetes - -For MinIO in production, consider: -- Setting up proper credentials (change default minioadmin/minioadmin) -- Configuring persistent storage -- Setting up proper networking and access controls -- Using multiple MinIO instances for high availability +This script generates properly configured environment files for both development and production environments. ## Docker Deployment ### Local Development with Docker -1. Set up the environment variables: +1. Set up the environment files: ```bash # For HTTP/WS ./update-docker-env.sh @@ -401,8 +393,6 @@ For MinIO in production, consider: # For HTTPS/WSS ./update-docker-env.sh localhost true ``` - - This will create a `.env` file with default settings for local development. 2. Run the application using Docker Compose: ```bash @@ -417,7 +407,7 @@ For MinIO in production, consider: When deploying to a remote server: -1. Set up the environment variables with your server's hostname: +1. Set up the environment files with your server's hostname: ```bash # For HTTP/WS ./update-docker-env.sh your-server-hostname diff --git a/docker-compose.yml b/docker-compose.yml index 8c6a831e..ebb7e028 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,8 @@ services: depends_on: backend: condition: service_started - environment: - - VITE_API_URL=${VITE_API_URL:-http://backend:3000} - - VITE_SOCKET_URL=${VITE_SOCKET_URL:-ws://backend:3000} + env_file: + - ./worklenz-frontend/.env.production networks: - worklenz @@ -23,36 +22,8 @@ services: condition: service_healthy minio: condition: service_started - environment: - - AWS_REGION=${AWS_REGION:-us-east-1} - - BACKEND_PUBLIC_DIR - - BACKEND_VIEWS_DIR - - COMMIT_BUILD_IMMEDIATELY - - COOKIE_SECRET - - DB_HOST=${DB_HOST:-db} - - DB_MAX_CLIENTS - - DB_NAME=${DB_NAME:-worklenz_db} - - DB_PASSWORD=${DB_PASSWORD:-password} - - DB_PORT=${DB_PORT:-5432} - - DB_USER=${DB_USER:-postgres} - - GOOGLE_CALLBACK_URL - - GOOGLE_CLIENT_ID - - GOOGLE_CLIENT_SECRET - - HOSTNAME - - LOGIN_FAILURE_REDIRECT - - NODE_ENV=${NODE_ENV:-development} - - PORT=${PORT:-3000} - - SESSION_NAME - - SESSION_SECRET - - SLACK_WEBHOOK - - SOCKET_IO_CORS - - SOURCE_EMAIL - - USE_PG_NATIVE - - STORAGE_PROVIDER=${STORAGE_PROVIDER:-s3} - - AWS_BUCKET=${BUCKET:-worklenz-bucket} - - AWS_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID:-minioadmin} - - AWS_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY:-minioadmin} - - S3_URL=${S3_URL:-http://minio:9000} + env_file: + - ./worklenz-backend/.env networks: - worklenz diff --git a/update-docker-env.sh b/update-docker-env.sh index 1ba25997..cabcfab5 100755 --- a/update-docker-env.sh +++ b/update-docker-env.sh @@ -19,32 +19,108 @@ else WS_PREFIX="ws://" fi -# Create or update root .env file -cat > .env << EOL -# Frontend Configuration +# Create or overwrite frontend .env.development file +mkdir -p worklenz-frontend +cat > worklenz-frontend/.env.development << EOL +# API Connection +VITE_API_URL=http://localhost:3000 +VITE_SOCKET_URL=ws://localhost:3000 + +# Application Environment +VITE_APP_TITLE=Worklenz +VITE_APP_ENV=development + +# Mixpanel +VITE_MIXPANEL_TOKEN= + +# Recaptcha +VITE_ENABLE_RECAPTCHA=false +VITE_RECAPTCHA_SITE_KEY= + +# Session ID +VITE_WORKLENZ_SESSION_ID=worklenz-session-id +EOL + +# Create frontend .env.production file +cat > worklenz-frontend/.env.production << EOL +# API Connection VITE_API_URL=${HTTP_PREFIX}${HOSTNAME}:3000 VITE_SOCKET_URL=${WS_PREFIX}${HOSTNAME}:3000 -# Backend Configuration +# Application Environment +VITE_APP_TITLE=Worklenz +VITE_APP_ENV=production + +# Mixpanel +VITE_MIXPANEL_TOKEN= + +# Recaptcha +VITE_ENABLE_RECAPTCHA=false +VITE_RECAPTCHA_SITE_KEY= + +# Session ID +VITE_WORKLENZ_SESSION_ID=worklenz-session-id +EOL + +# Create backend environment file +mkdir -p worklenz-backend +cat > worklenz-backend/.env << EOL +# Server +NODE_ENV=production +PORT=3000 +SESSION_NAME=worklenz.sid +SESSION_SECRET=change_me_in_production +COOKIE_SECRET=change_me_in_production + +# CORS +SOCKET_IO_CORS=${HTTP_PREFIX}${HOSTNAME}:5000 +SERVER_CORS=${HTTP_PREFIX}${HOSTNAME}:5000 + +# Database DB_HOST=db DB_PORT=5432 DB_USER=postgres DB_PASSWORD=password DB_NAME=worklenz_db -NODE_ENV=development -PORT=3000 +DB_MAX_CLIENTS=50 +USE_PG_NATIVE=true # Storage Configuration -AWS_REGION=us-east-1 STORAGE_PROVIDER=s3 -BUCKET=worklenz-bucket -S3_ACCESS_KEY_ID=minioadmin -S3_SECRET_ACCESS_KEY=minioadmin +AWS_REGION=us-east-1 +AWS_BUCKET=worklenz-bucket +AWS_ACCESS_KEY_ID=minioadmin +AWS_SECRET_ACCESS_KEY=minioadmin S3_URL=http://minio:9000 + +# Backend Directories +BACKEND_PUBLIC_DIR=./public +BACKEND_VIEWS_DIR=./views + +# Host +HOSTNAME=${HOSTNAME} +FRONTEND_URL=${HTTP_PREFIX}${HOSTNAME}:5000 + +# Email +SOURCE_EMAIL=no-reply@example.com + +# Notifications +SLACK_WEBHOOK= + +# Other Settings +COMMIT_BUILD_IMMEDIATELY=true + +# JWT Secret +JWT_SECRET=change_me_in_production EOL echo "Environment configuration updated for ${HOSTNAME} with" $([ "$USE_SSL" = "true" ] && echo "HTTPS/WSS" || echo "HTTP/WS") +echo "Created/updated environment files:" +echo "- worklenz-frontend/.env.development (development)" +echo "- worklenz-frontend/.env.production (production build)" +echo "- worklenz-backend/.env" +echo echo "To run with Docker Compose, use: docker-compose up -d" echo -echo "API URL: ${VITE_API_URL:-${HTTP_PREFIX}${HOSTNAME}:3000}" -echo "Socket URL: ${VITE_SOCKET_URL:-${WS_PREFIX}${HOSTNAME}:3000}" \ No newline at end of file +echo "Production API URL: ${HTTP_PREFIX}${HOSTNAME}:3000" +echo "Production Socket URL: ${WS_PREFIX}${HOSTNAME}:3000" \ No newline at end of file diff --git a/worklenz-backend/.env.example b/worklenz-backend/.env.example deleted file mode 100644 index 145f2411..00000000 --- a/worklenz-backend/.env.example +++ /dev/null @@ -1,76 +0,0 @@ -# Server -NODE_ENV=development -PORT=3000 -SESSION_NAME=worklenz.sid -SESSION_SECRET="your_session_secret" -COOKIE_SECRET="your_cookie_secret" - -# CORS -SOCKET_IO_CORS=http://localhost:5000 -SERVER_CORS=* - -# Database -DB_USER=postgres -DB_PASSWORD=your_db_password -DB_NAME=worklenz_db -DB_HOST=localhost -DB_PORT=5432 -DB_MAX_CLIENTS=50 - -# Google Login -GOOGLE_CLIENT_ID="your_google_client_id" -GOOGLE_CLIENT_SECRET="your_google_client_secret" -GOOGLE_CALLBACK_URL="http://localhost:5000/secure/google/verify" -LOGIN_FAILURE_REDIRECT="http://localhost:5000/auth/authenticating" -LOGIN_SUCCESS_REDIRECT="http://localhost:5000/auth/authenticating" - -# CLI -ANGULAR_DIST_DIR="path/to/frontend/dist" -ANGULAR_SRC_DIR="path/to/frontend" -BACKEND_PUBLIC_DIR="path/to/backend/public" -BACKEND_VIEWS_DIR="path/to/backend/views" -COMMIT_BUILD_IMMEDIATELY=false - -# HOST -HOSTNAME=localhost:5000 - -# SLACK -SLACK_WEBHOOK=your_slack_webhook_url -USE_PG_NATIVE=false - -# JWT SECRET -JWT_SECRET=your_jwt_secret - -# FRONTEND_URL -FRONTEND_URL=http://localhost:5000 - -# STORAGE -STORAGE_PROVIDER=s3 # values s3 or azure - -# AWS -AWS_REGION="your_aws_region" -AWS_ACCESS_KEY_ID="your_aws_access_key_id" -AWS_SECRET_ACCESS_KEY="your_aws_secret_access_key" -AWS_BUCKET="your_s3_bucket" -S3_URL="your_s3_url" - -# Azure Storage -AZURE_STORAGE_ACCOUNT_NAME="your_storage_account_name" -AZURE_STORAGE_CONTAINER="your_storage_container" -AZURE_STORAGE_ACCOUNT_KEY="your_storage_account_key" -AZURE_STORAGE_URL="your_storage_url" - -# DIRECTPAY -DP_STAGE=DEV -DP_URL=your_url -DP_MERCHANT_ID=your_merchant_id -DP_SECRET_KEY=your_secret_key -DP_API_KEY=your_api_key - -CONTACT_US_EMAIL=support@example.com - -GOOGLE_CAPTCHA_SECRET_KEY=your_captcha_secret_key -GOOGLE_CAPTCHA_PASS_SCORE=0.8 - -# Email Cronjobs -ENABLE_EMAIL_CRONJOBS=true \ No newline at end of file From 54642037d3d1d88a1ad639450fae6e6646653c9f Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 13:02:29 +0530 Subject: [PATCH 6/9] Enhance environment configuration for frontend and CORS support - Updated update-docker-env.sh to define FRONTEND_URL and streamline CORS settings. - Modified app.ts to include SERVER_CORS and FRONTEND_URL in allowed origins for both production and development environments. - Improved output messages in update-docker-env.sh to provide clearer information on URLs and CORS configuration. --- update-docker-env.sh | 15 ++++++++++----- worklenz-backend/src/app.ts | 12 ++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/update-docker-env.sh b/update-docker-env.sh index cabcfab5..c5274d7c 100755 --- a/update-docker-env.sh +++ b/update-docker-env.sh @@ -19,6 +19,9 @@ else WS_PREFIX="ws://" fi +# Frontend URLs +FRONTEND_URL="${HTTP_PREFIX}${HOSTNAME}:5000" + # Create or overwrite frontend .env.development file mkdir -p worklenz-frontend cat > worklenz-frontend/.env.development << EOL @@ -73,8 +76,8 @@ SESSION_SECRET=change_me_in_production COOKIE_SECRET=change_me_in_production # CORS -SOCKET_IO_CORS=${HTTP_PREFIX}${HOSTNAME}:5000 -SERVER_CORS=${HTTP_PREFIX}${HOSTNAME}:5000 +SOCKET_IO_CORS=${FRONTEND_URL} +SERVER_CORS=${FRONTEND_URL} # Database DB_HOST=db @@ -99,7 +102,7 @@ BACKEND_VIEWS_DIR=./views # Host HOSTNAME=${HOSTNAME} -FRONTEND_URL=${HTTP_PREFIX}${HOSTNAME}:5000 +FRONTEND_URL=${FRONTEND_URL} # Email SOURCE_EMAIL=no-reply@example.com @@ -122,5 +125,7 @@ echo "- worklenz-backend/.env" echo echo "To run with Docker Compose, use: docker-compose up -d" echo -echo "Production API URL: ${HTTP_PREFIX}${HOSTNAME}:3000" -echo "Production Socket URL: ${WS_PREFIX}${HOSTNAME}:3000" \ No newline at end of file +echo "Frontend URL: ${FRONTEND_URL}" +echo "API URL: ${HTTP_PREFIX}${HOSTNAME}:3000" +echo "Socket URL: ${WS_PREFIX}${HOSTNAME}:3000" +echo "CORS is configured to allow requests from: ${FRONTEND_URL}" \ No newline at end of file diff --git a/worklenz-backend/src/app.ts b/worklenz-backend/src/app.ts index 28ed9095..4da00a0e 100644 --- a/worklenz-backend/src/app.ts +++ b/worklenz-backend/src/app.ts @@ -55,16 +55,20 @@ const allowedOrigins = [ isProduction() ? [ `http://localhost:5000`, - `http://127.0.0.1:5000` - ] + `http://127.0.0.1:5000`, + process.env.SERVER_CORS || "", // Add hostname from env + process.env.FRONTEND_URL || "" // Support FRONTEND_URL as well + ].filter(Boolean) // Remove empty strings : [ "http://localhost:3000", "http://localhost:5173", "http://127.0.0.1:5173", "http://127.0.0.1:3000", "http://127.0.0.1:5000", - `http://localhost:5000` - ] + `http://localhost:5000`, + process.env.SERVER_CORS || "", // Add hostname from env + process.env.FRONTEND_URL || "" // Support FRONTEND_URL as well + ].filter(Boolean) // Remove empty strings ].flat(); app.use(cors({ From b9e5f396fdee5d9401f717151527d046c10bb4bf Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 15:20:39 +0530 Subject: [PATCH 7/9] Refactor frontend service configuration in docker-compose.yml - Changed the frontend service to build from a local context instead of using a pre-built image. - Specified the Dockerfile for the frontend build process. --- docker-compose.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ebb7e028..2008f850 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,8 @@ services: frontend: - image: docker.io/chamikajaycey/worklenz-frontend:latest + build: + context: ./worklenz-frontend + dockerfile: Dockerfile container_name: worklenz_frontend ports: - "5000:5000" From 79e8bb37349d04ee588339fd867b25ad16791c09 Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 15:36:52 +0530 Subject: [PATCH 8/9] Refactor start.sh script creation in Dockerfile - Updated the Dockerfile to create the start.sh script in a more structured manner, improving readability and maintainability. - Ensured that the script dynamically updates env-config.js with runtime environment variables for API and WebSocket URLs. --- worklenz-frontend/Dockerfile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/worklenz-frontend/Dockerfile b/worklenz-frontend/Dockerfile index f1e98751..37dffae6 100644 --- a/worklenz-frontend/Dockerfile +++ b/worklenz-frontend/Dockerfile @@ -23,15 +23,15 @@ RUN npm install -g serve COPY --from=build /app/build /app/build COPY --from=build /app/public/env-config.js /app/build/env-config.js -# Create a script to start server and dynamically update env-config.js -RUN echo '#!/bin/sh\n\ -# Update env-config.js with runtime environment variables\n\ -cat > /app/build/env-config.js << EOL\n\ -window.VITE_API_URL="${VITE_API_URL:-http://backend:3000}";\n\ -window.VITE_SOCKET_URL="${VITE_SOCKET_URL:-ws://backend:3000}";\n\ -EOL\n\ -exec serve -s build -l 5000' > /app/start.sh && \ -chmod +x /app/start.sh +# Create start.sh script +RUN echo '#!/bin/sh' > /app/start.sh && \ + echo '# Update env-config.js with runtime environment variables' >> /app/start.sh && \ + echo 'cat > /app/build/env-config.js << EOL' >> /app/start.sh && \ + echo 'window.VITE_API_URL="${VITE_API_URL:-http://backend:3000}";' >> /app/start.sh && \ + echo 'window.VITE_SOCKET_URL="${VITE_SOCKET_URL:-ws://backend:3000}";' >> /app/start.sh && \ + echo 'EOL' >> /app/start.sh && \ + echo 'exec serve -s build -l 5000' >> /app/start.sh && \ + chmod +x /app/start.sh EXPOSE 5000 CMD ["/app/start.sh"] \ No newline at end of file From bf1d48709c19e36c489430257dfad61348a03dfe Mon Sep 17 00:00:00 2001 From: chamiakJ Date: Mon, 28 Apr 2025 16:22:54 +0530 Subject: [PATCH 9/9] Enhance backend API with health check endpoint and update environment script - Added a new health check endpoint to the public router in index.ts, returning a simple status response. - Updated update-docker-env.sh to include the MinIO Dashboard URL in the environment configuration and output messages. --- update-docker-env.sh | 2 ++ worklenz-backend/src/routes/public/index.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/update-docker-env.sh b/update-docker-env.sh index c5274d7c..bfcca1ae 100755 --- a/update-docker-env.sh +++ b/update-docker-env.sh @@ -21,6 +21,7 @@ fi # Frontend URLs FRONTEND_URL="${HTTP_PREFIX}${HOSTNAME}:5000" +MINIO_DASHBOARD_URL="${HTTP_PREFIX}${HOSTNAME}:9001" # Create or overwrite frontend .env.development file mkdir -p worklenz-frontend @@ -128,4 +129,5 @@ echo echo "Frontend URL: ${FRONTEND_URL}" echo "API URL: ${HTTP_PREFIX}${HOSTNAME}:3000" echo "Socket URL: ${WS_PREFIX}${HOSTNAME}:3000" +echo "MinIO Dashboard URL: ${MINIO_DASHBOARD_URL}" echo "CORS is configured to allow requests from: ${FRONTEND_URL}" \ No newline at end of file diff --git a/worklenz-backend/src/routes/public/index.ts b/worklenz-backend/src/routes/public/index.ts index 956c4ab4..5d088d6c 100644 --- a/worklenz-backend/src/routes/public/index.ts +++ b/worklenz-backend/src/routes/public/index.ts @@ -5,5 +5,8 @@ import safeControllerFunction from "../../shared/safe-controller-function"; const public_router = express.Router(); public_router.post("/new-subscriber", safeControllerFunction(ClientsController.addSubscriber)); +public_router.get("/health", (req, res) => { + res.status(200).json({ status: "ok" }); +}); export default public_router;