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 92ed1a90..a6885d95 100644 --- a/README.md +++ b/README.md @@ -358,34 +358,88 @@ 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. +This script generates properly configured environment files for both development and production environments. -## Development +## Docker Deployment -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. +### Local Development with Docker -## Production Deployment +1. Set up the environment files: + ```bash + # For HTTP/WS + ./update-docker-env.sh + + # For HTTPS/WSS + ./update-docker-env.sh localhost true + ``` -For production deployment: +2. Run the application using Docker Compose: + ```bash + docker-compose up -d + ``` -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 +3. Access the application: + - Frontend: http://localhost:5000 + - Backend API: http://localhost:3000 (or https://localhost:3000 with SSL) -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 +### Remote Server Deployment + +When deploying to a remote server: + +1. Set up the environment files 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. + +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) + - `VITE_SOCKET_URL`: WebSocket URL for real-time communication (default: ws://backend:3000) + +- 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 02dab3ee..2008f850 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,16 @@ services: frontend: - image: docker.io/chamikajaycey/worklenz-frontend:latest + build: + context: ./worklenz-frontend + dockerfile: Dockerfile container_name: worklenz_frontend ports: - "5000:5000" depends_on: backend: condition: service_started + env_file: + - ./worklenz-frontend/.env.production networks: - worklenz @@ -20,36 +24,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 @@ -113,7 +89,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/update-docker-env.sh b/update-docker-env.sh new file mode 100755 index 00000000..bfcca1ae --- /dev/null +++ b/update-docker-env.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +# Script to set environment variables for Docker deployment +# 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 + +# 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 +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 + +# 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=${FRONTEND_URL} +SERVER_CORS=${FRONTEND_URL} + +# Database +DB_HOST=db +DB_PORT=5432 +DB_USER=postgres +DB_PASSWORD=password +DB_NAME=worklenz_db +DB_MAX_CLIENTS=50 +USE_PG_NATIVE=true + +# Storage Configuration +STORAGE_PROVIDER=s3 +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=${FRONTEND_URL} + +# 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 "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/.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 diff --git a/worklenz-backend/src/app.ts b/worklenz-backend/src/app.ts index 4fead2d9..4da00a0e 100644 --- a/worklenz-backend/src/app.ts +++ b/worklenz-backend/src/app.ts @@ -55,21 +55,25 @@ 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({ 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); 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; diff --git a/worklenz-frontend/Dockerfile b/worklenz-frontend/Dockerfile index ac1f820f..37dffae6 100644 --- a/worklenz-frontend/Dockerfile +++ b/worklenz-frontend/Dockerfile @@ -7,6 +7,11 @@ 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 && \ + echo "window.VITE_SOCKET_URL='${VITE_SOCKET_URL:-ws://backend:3000}';" >> ./public/env-config.js + RUN npm run build FROM node:22-alpine AS production @@ -16,5 +21,17 @@ 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 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 ["serve", "-s", "build", "-l", "5000"] \ No newline at end of file +CMD ["/app/start.sh"] \ No newline at end of file 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..948a0c70 --- /dev/null +++ b/worklenz-frontend/src/config/env.ts @@ -0,0 +1,56 @@ +/** + * Environment configuration + * 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; + } +} + +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 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',