From 6bf1b2ae8a4a46ee64f31314fb00127c68cb7775 Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:24:36 -0600 Subject: [PATCH 1/7] docs: remove QUICKSTART-TESTING.md and update access points in QUICKSTART.md and README.md - Deleted the outdated QUICKSTART-TESTING.md file as it contained redundant testing instructions. - Updated access points in QUICKSTART.md and README.md to reflect the new Nginx configuration and service URLs. - Added notes regarding the frontend build process and Nginx serving static files. --- QUICKSTART-TESTING.md | 222 ------------------------------------------ QUICKSTART.md | 45 +++++++-- README.md | 23 +++-- docker/nginx.conf | 2 +- frontend/Dockerfile | 3 + 5 files changed, 55 insertions(+), 240 deletions(-) delete mode 100644 QUICKSTART-TESTING.md diff --git a/QUICKSTART-TESTING.md b/QUICKSTART-TESTING.md deleted file mode 100644 index 43502df..0000000 --- a/QUICKSTART-TESTING.md +++ /dev/null @@ -1,222 +0,0 @@ -# Testing Quick Start Guide - -Get up and running with ProjectHub tests in minutes! - -## Quick Setup - -### Backend Tests - -⚠️ **IMPORTANT:** The application uses old package versions that require **Python 3.7 or 3.8** -They will NOT work with Python 3.9+ or 3.13. - -**With Python 3.8 (Recommended):** - -```powershell -# Windows - Create Python 3.8 virtual environment -py -3.8 -m venv venv38 -.\venv38\Scripts\Activate.ps1 - -# Navigate to backend and install -cd backend -pip install -r requirements-test.txt - -# Run tests -pytest -v -``` - -```bash -# Linux/macOS -python3.8 -m venv venv38 -source venv38/bin/activate -cd backend -pip install -r requirements-test.txt -pytest -v -``` - -> **Note:** See `backend/PYTHON-COMPATIBILITY.md` for detailed Python version information and upgrade options. - -### Frontend Tests - -```bash -# 1. Navigate to frontend directory -cd frontend - -# 2. Install dependencies -npm install - -# 3. Run tests -npm test -- --watchAll=false -``` - -## Run All Tests (One Command) - -### Linux/macOS - -```bash -# Make script executable (first time only) -chmod +x run-tests.sh - -# Run all tests -./run-tests.sh -``` - -### Windows (PowerShell) - -```powershell -# Run all tests -.\run-tests.ps1 -``` - -## Generate Coverage Reports - -### Linux/macOS - -```bash -chmod +x run-tests-coverage.sh -./run-tests-coverage.sh -``` - -Then open: -- Backend: `backend/htmlcov/index.html` -- Frontend: `frontend/coverage/lcov-report/index.html` - -### Windows (PowerShell) - -```powershell -# Backend coverage -cd backend -pytest --cov=. --cov-report=html -# Open: backend\htmlcov\index.html - -# Frontend coverage -cd ..\frontend -npm run test:coverage -# Open: frontend\coverage\lcov-report\index.html -``` - -## What's Being Tested? - -### Backend (Python/Flask) -✅ **Models** - User, Project, Task, Message, Document -✅ **Authentication** - JWT tokens, login, permissions -✅ **API Routes** - Projects, Tasks, Documents -✅ **Utilities** - Date formatting, file handling, logging - -**Test Files:** -- `backend/tests/test_models.py` -- `backend/tests/test_auth.py` -- `backend/tests/test_routes_projects.py` -- `backend/tests/test_routes_tasks.py` -- `backend/tests/test_utils.py` - -### Frontend (React) -✅ **Components** - Dashboard, Login, TaskList, ProjectDetail -✅ **API Service** - HTTP requests, token management -✅ **User Interactions** - Clicks, form submissions, navigation -✅ **Error Handling** - API errors, loading states - -**Test Files:** -- `frontend/src/components/__tests__/Dashboard.test.js` -- `frontend/src/components/__tests__/Login.test.js` -- `frontend/src/components/__tests__/TaskList.test.js` -- `frontend/src/components/__tests__/ProjectDetail.test.js` -- `frontend/src/services/__tests__/api.test.js` - -## Common Commands - -### Backend - -```bash -# Run all tests -pytest - -# Run specific test file -pytest tests/test_models.py - -# Run with coverage -pytest --cov=. --cov-report=term - -# Run in verbose mode -pytest -v - -# Run specific test -pytest tests/test_models.py::TestUserModel::test_create_user -``` - -### Frontend - -```bash -# Run tests (watch mode) -npm test - -# Run tests once -npm test -- --watchAll=false - -# Run with coverage -npm run test:coverage - -# Run specific test file -npm test -- Dashboard.test.js - -# Update snapshots -npm test -- -u -``` - -## Troubleshooting - -### Backend: "ModuleNotFoundError" -```bash -cd backend -pip install -r requirements-test.txt -``` - -### Backend: "No module named 'pytest'" -```bash -pip install pytest pytest-cov pytest-flask -``` - -### Frontend: "Cannot find module" -```bash -cd frontend -rm -rf node_modules package-lock.json -npm install -``` - -### Frontend: Tests timeout -Increase timeout in test: -```javascript -jest.setTimeout(10000); // 10 seconds -``` - -## Next Steps - -- Read the full [Testing Guide](TESTING.md) -- Check out [Backend Test README](backend/tests/README.md) -- Check out [Frontend Test README](frontend/src/components/__tests__/README.md) - -## Test Statistics - -### Backend -- **Test Files**: 5 -- **Test Classes**: ~15 -- **Test Functions**: ~50+ -- **Coverage Goal**: >80% - -### Frontend -- **Test Files**: 5 -- **Test Suites**: 5 -- **Test Cases**: ~40+ -- **Coverage Goal**: >70% - -## Need Help? - -1. Check the full [TESTING.md](TESTING.md) documentation -2. Review example tests in the test directories -3. Consult the official documentation: - - [pytest docs](https://docs.pytest.org/) - - [React Testing Library](https://testing-library.com/react) - ---- - -**Happy Testing! 🧪** - diff --git a/QUICKSTART.md b/QUICKSTART.md index 7f7f86e..ad6956f 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -73,11 +73,13 @@ docker compose -f docker/docker-compose.yml up -d --build backend ## Access Points -- **Frontend**: http://localhost:3000 -- **Backend API**: http://localhost:5000 -- **Nginx**: http://localhost:80 +- **Main Application (via Nginx)**: http://localhost (or http://YOUR_SERVER_IP) +- **Backend API**: http://localhost/api (or http://YOUR_SERVER_IP/api) +- **Admin Dashboard**: http://localhost/api/admin (or http://YOUR_SERVER_IP/api/admin) - **Database**: localhost:5432 +**Note**: All services are accessible through Nginx on port 80. The frontend is built during Docker build and served as static files through Nginx. + ## Default Credentials **Application Users** (seeded automatically): @@ -97,17 +99,34 @@ docker compose -f docker/docker-compose.yml up -d --build backend ## First Time Setup -1. Build and start: +1. Build and start all services: ```bash docker compose -f docker/docker-compose.yml up -d --build ``` - -2. Wait for database seeding (automatic on first startup) + + This command will: + - Build the frontend (creates production build in `frontend/build/`) + - Build the backend container + - Start all services (database, backend, frontend, nginx) + +2. Wait for services to initialize: + - Database seeding happens automatically on first startup - Creates admin user and test users - Seeds projects, tasks, comments, messages (100 messages with 50 templates, spanning 6 months) - Creates document records + + Check logs to verify services are ready: + ```bash + docker compose -f docker/docker-compose.yml logs -f + ``` -3. Access the application at http://localhost:3000 +3. Access the application: + - **Local**: http://localhost + - **Remote Server**: http://YOUR_SERVER_IP (replace with your server's IP address) + + The application is served through Nginx on port 80, which proxies: + - Frontend static files (built during Docker build) + - Backend API requests to `/api/*` 4. Login with any of the default credentials (see above) @@ -143,9 +162,15 @@ docker compose -f docker/docker-compose.yml up -d - Check backend logs: `docker compose -f docker/docker-compose.yml logs backend` - Verify database is accessible -**Frontend not loading?** -- Check frontend logs: `docker compose -f docker/docker-compose.yml logs frontend` -- Ensure frontend compiled successfully (look for "Compiled successfully!") +**Frontend not loading (403 Forbidden)?** +- Ensure frontend was built during Docker build: `docker compose -f docker/docker-compose.yml logs frontend | grep -i build` +- Check that `frontend/build` directory exists and contains `index.html` +- Verify nginx can access the build directory: `docker compose -f docker/docker-compose.yml exec nginx ls -la /usr/share/nginx/html` +- Rebuild if needed: `docker compose -f docker/docker-compose.yml up -d --build frontend nginx` + +**Nginx 403 errors?** +- Frontend build may be missing. Rebuild: `docker compose -f docker/docker-compose.yml up -d --build` +- Check nginx logs: `docker compose -f docker/docker-compose.yml logs nginx` **Database connection errors?** - Ensure database container is running diff --git a/README.md b/README.md index 3324ba6..bbbc002 100644 --- a/README.md +++ b/README.md @@ -90,11 +90,13 @@ docker compose -f docker/docker-compose.yml build --no-cache docker compose -f docker/docker-compose.yml up -d ``` -**Build and start in one command:** +**Build and start in one command (recommended):** ```bash docker compose -f docker/docker-compose.yml up -d --build ``` +**Note**: The frontend is automatically built during the Docker build process. The production build is created in `frontend/build/` and served by Nginx on port 80. + #### Shutdown **Stop all services (keeps containers):** @@ -148,15 +150,22 @@ cd ProjectHub docker compose -f docker/docker-compose.yml up -d --build ``` + **What happens during build:** + - Frontend is built (production build created in `frontend/build/`) + - Backend dependencies are installed + - Database container is prepared + - Nginx is configured to serve the built frontend files + 3. Wait for services to initialize (database seeding happens automatically on first startup) 4. Access the application: -- **Frontend**: http://localhost:3000 -- **Backend API**: http://localhost:5000 -- **Admin Dashboard**: http://localhost:5000/admin -- **API Health Check**: http://localhost:5000/api/health -- **Nginx (Production)**: http://localhost:80 -- **Database**: localhost:5432 + - **Main Application (via Nginx)**: http://localhost (or http://YOUR_SERVER_IP) + - **Backend API**: http://localhost/api (or http://YOUR_SERVER_IP/api) + - **Admin Dashboard**: http://localhost/api/admin (or http://YOUR_SERVER_IP/api/admin) + - **API Health Check**: http://localhost/api/health (or http://YOUR_SERVER_IP/api/health) + - **Database**: localhost:5432 + + **Note**: The frontend is served through Nginx on port 80. The frontend development server (port 3000) is also available but not needed for normal use. ### Database Seeding diff --git a/docker/nginx.conf b/docker/nginx.conf index 8473694..b9b31c0 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -29,7 +29,7 @@ http { # Backend API location /api/ { - proxy_pass http://backend:5000; + proxy_pass http://backend:5000/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 88ccfcd..6f87f20 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -11,6 +11,9 @@ RUN npm install # Copy application code COPY . . +# Build the production version +RUN npm run build + # Expose port EXPOSE 3000 From 3dfd6a557aa5af602529259b5026d3d6855370af Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:31:45 -0600 Subject: [PATCH 2/7] docs: update QUICKSTART and README for improved setup instructions and frontend build process - Revised the first-time setup instructions in QUICKSTART.md and README.md to include repository cloning steps. - Clarified the automatic database seeding and service initialization process. - Updated notes on the frontend build process, emphasizing that it occurs automatically and is served through Nginx. - Adjusted Docker Compose configuration to use named volumes for frontend build output, enhancing container management. --- QUICKSTART.md | 43 ++++++++++++++++++----------------- README.md | 16 ++++++------- docker/docker-compose.yml | 4 +++- frontend/Dockerfile | 7 +++--- frontend/docker-entrypoint.sh | 22 ++++++++++++++++++ 5 files changed, 58 insertions(+), 34 deletions(-) create mode 100644 frontend/docker-entrypoint.sh diff --git a/QUICKSTART.md b/QUICKSTART.md index ad6956f..cc9b5d1 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -99,37 +99,38 @@ docker compose -f docker/docker-compose.yml up -d --build backend ## First Time Setup -1. Build and start all services: +1. Clone the repository (if not already cloned): + ```bash + git clone + cd ProjectHub + ``` + +2. Build and start all services: ```bash docker compose -f docker/docker-compose.yml up -d --build ``` - This command will: - - Build the frontend (creates production build in `frontend/build/`) + **That's it!** This single command will: + - Build the frontend (production build happens automatically) - Build the backend container - Start all services (database, backend, frontend, nginx) + - Automatically seed the database with test data on first startup -2. Wait for services to initialize: - - Database seeding happens automatically on first startup - - Creates admin user and test users - - Seeds projects, tasks, comments, messages (100 messages with 50 templates, spanning 6 months) - - Creates document records - - Check logs to verify services are ready: - ```bash - docker compose -f docker/docker-compose.yml logs -f - ``` - -3. Access the application: +3. Wait a few seconds for services to initialize, then access the application: - **Local**: http://localhost - **Remote Server**: http://YOUR_SERVER_IP (replace with your server's IP address) The application is served through Nginx on port 80, which proxies: - - Frontend static files (built during Docker build) + - Frontend static files (automatically built) - Backend API requests to `/api/*` 4. Login with any of the default credentials (see above) +**Optional**: Check logs to verify services are ready: +```bash +docker compose -f docker/docker-compose.yml logs -f +``` + ## Re-seeding Database To reset and re-seed the database (⚠️ deletes all data): @@ -163,13 +164,13 @@ docker compose -f docker/docker-compose.yml up -d - Verify database is accessible **Frontend not loading (403 Forbidden)?** -- Ensure frontend was built during Docker build: `docker compose -f docker/docker-compose.yml logs frontend | grep -i build` -- Check that `frontend/build` directory exists and contains `index.html` -- Verify nginx can access the build directory: `docker compose -f docker/docker-compose.yml exec nginx ls -la /usr/share/nginx/html` -- Rebuild if needed: `docker compose -f docker/docker-compose.yml up -d --build frontend nginx` +- Wait a few seconds for the frontend build to complete (check logs: `docker compose -f docker/docker-compose.yml logs frontend`) +- Verify nginx can access the build files: `docker compose -f docker/docker-compose.yml exec nginx ls -la /usr/share/nginx/html` +- Rebuild if needed: `docker compose -f docker/docker-compose.yml up -d --build` **Nginx 403 errors?** -- Frontend build may be missing. Rebuild: `docker compose -f docker/docker-compose.yml up -d --build` +- Frontend build may still be in progress. Wait 30-60 seconds and refresh +- Check frontend logs: `docker compose -f docker/docker-compose.yml logs frontend` - Check nginx logs: `docker compose -f docker/docker-compose.yml logs nginx` **Database connection errors?** diff --git a/README.md b/README.md index bbbc002..91a2023 100644 --- a/README.md +++ b/README.md @@ -150,22 +150,20 @@ cd ProjectHub docker compose -f docker/docker-compose.yml up -d --build ``` - **What happens during build:** - - Frontend is built (production build created in `frontend/build/`) - - Backend dependencies are installed - - Database container is prepared - - Nginx is configured to serve the built frontend files + **That's it!** The command will: + - Build the frontend (production build) + - Build the backend container + - Start all services (database, backend, frontend, nginx) + - Automatically seed the database with test data -3. Wait for services to initialize (database seeding happens automatically on first startup) - -4. Access the application: +3. Wait a few seconds for services to initialize, then access the application: - **Main Application (via Nginx)**: http://localhost (or http://YOUR_SERVER_IP) - **Backend API**: http://localhost/api (or http://YOUR_SERVER_IP/api) - **Admin Dashboard**: http://localhost/api/admin (or http://YOUR_SERVER_IP/api/admin) - **API Health Check**: http://localhost/api/health (or http://YOUR_SERVER_IP/api/health) - **Database**: localhost:5432 - **Note**: The frontend is served through Nginx on port 80. The frontend development server (port 3000) is also available but not needed for normal use. + **Note**: The frontend is automatically built and served through Nginx on port 80. No additional build steps required. ### Database Seeding diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 3080d50..d598362 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -49,6 +49,7 @@ services: volumes: - ../frontend:/app - /app/node_modules + - frontend_build:/build-output depends_on: - backend networks: @@ -60,7 +61,7 @@ services: - "80:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf - - ../frontend/build:/usr/share/nginx/html + - frontend_build:/usr/share/nginx/html depends_on: - frontend networks: @@ -70,6 +71,7 @@ volumes: postgres_data: uploads: logs: + frontend_build: networks: app-network: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 6f87f20..2551143 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -11,11 +11,12 @@ RUN npm install # Copy application code COPY . . -# Build the production version -RUN npm run build +# Copy entrypoint script +COPY docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh # Expose port EXPOSE 3000 -CMD ["npm", "start"] +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh new file mode 100644 index 0000000..0be9458 --- /dev/null +++ b/frontend/docker-entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +# Build the frontend +echo "Building frontend..." +npm run build + +# Copy build files to shared volume if it exists +if [ -d "/build-output" ]; then + echo "Copying build files to shared volume..." + # Clear destination and copy all files including hidden ones + rm -rf /build-output/* /build-output/.[!.]* /build-output/..?* 2>/dev/null || true + cp -r /app/build/. /build-output/ + echo "Build files copied successfully" +else + echo "Warning: /build-output directory not found, build files not copied to shared volume" +fi + +# Start the development server (for hot-reload during development) +# In production, this container could exit after building +exec npm start + From 173693c3e1f402a38a128ef8e8383698b6c5b377 Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:35:40 -0600 Subject: [PATCH 3/7] docs: update Admin Dashboard URL in QUICKSTART and README - Corrected the Admin Dashboard access URL in QUICKSTART.md and README.md to reflect the new routing configuration. - Adjusted Nginx configuration to properly route requests to the Admin Dashboard. - Updated frontend API base URL to use a relative path for improved compatibility with Nginx proxy settings. --- QUICKSTART.md | 2 +- README.md | 2 +- docker/nginx.conf | 18 +++++++++++++----- frontend/src/services/api.js | 6 +++--- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/QUICKSTART.md b/QUICKSTART.md index cc9b5d1..95c1349 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -75,7 +75,7 @@ docker compose -f docker/docker-compose.yml up -d --build backend - **Main Application (via Nginx)**: http://localhost (or http://YOUR_SERVER_IP) - **Backend API**: http://localhost/api (or http://YOUR_SERVER_IP/api) -- **Admin Dashboard**: http://localhost/api/admin (or http://YOUR_SERVER_IP/api/admin) +- **Admin Dashboard**: http://localhost/admin (or http://YOUR_SERVER_IP/admin) - **Database**: localhost:5432 **Note**: All services are accessible through Nginx on port 80. The frontend is built during Docker build and served as static files through Nginx. diff --git a/README.md b/README.md index 91a2023..c3eb34b 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ docker compose -f docker/docker-compose.yml up -d --build 3. Wait a few seconds for services to initialize, then access the application: - **Main Application (via Nginx)**: http://localhost (or http://YOUR_SERVER_IP) - **Backend API**: http://localhost/api (or http://YOUR_SERVER_IP/api) - - **Admin Dashboard**: http://localhost/api/admin (or http://YOUR_SERVER_IP/api/admin) + - **Admin Dashboard**: http://localhost/admin (or http://YOUR_SERVER_IP/admin) - **API Health Check**: http://localhost/api/health (or http://YOUR_SERVER_IP/api/health) - **Database**: localhost:5432 diff --git a/docker/nginx.conf b/docker/nginx.conf index b9b31c0..8d2621a 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -20,11 +20,12 @@ http { autoindex on; } - # Frontend - location / { - root /usr/share/nginx/html; - index index.html; - try_files $uri $uri/ /index.html; + # Admin dashboard (must come before /api/ to avoid matching /api/admin) + location /admin { + proxy_pass http://backend:5000/admin; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # Backend API @@ -39,6 +40,13 @@ http { add_header Access-Control-Allow-Headers "Authorization, Content-Type" always; } + # Frontend (must come last as catch-all) + location / { + root /usr/share/nginx/html; + index index.html; + try_files $uri $uri/ /index.html; + } + location /uploads/ { alias /app/uploads/; autoindex on; diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 0280035..b8beafc 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -5,9 +5,9 @@ const getApiBaseUrl = () => { if (process.env.REACT_APP_API_URL) { return process.env.REACT_APP_API_URL; } - // Use the same host as the frontend, but port 5000 - const hostname = window.location.hostname; - return `http://${hostname}:5000/api`; + // Use relative path - nginx will proxy to backend + // This works because frontend is served through nginx on port 80 + return '/api'; }; const API_BASE_URL = getApiBaseUrl(); From 9529dd6a4e112cbddc1326a4d4c227826a215315 Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:39:29 -0600 Subject: [PATCH 4/7] fix: update Nginx configuration for API routing - Modified the Nginx configuration to change the proxy_pass directive for the /api/ location, removing the trailing path to ensure proper routing to the backend service. --- docker/nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/nginx.conf b/docker/nginx.conf index 8d2621a..227340c 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -30,7 +30,7 @@ http { # Backend API location /api/ { - proxy_pass http://backend:5000/api/; + proxy_pass http://backend:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; From 96207529c1ff9401e61bfbd3e605ae156add620e Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:44:48 -0600 Subject: [PATCH 5/7] feat: enhance CORS support in Nginx configuration and improve error handling in UserManagement component - Added CORS headers to handle preflight requests in the Nginx configuration for the /api/ location. - Improved error handling in UserManagement component to provide more detailed error messages, including status codes and specific error responses. --- docker/nginx.conf | 11 +++++++++++ frontend/src/components/UserManagement.js | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docker/nginx.conf b/docker/nginx.conf index 227340c..a84fae9 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -30,6 +30,17 @@ http { # Backend API location /api/ { + # Handle CORS preflight requests + if ($request_method = 'OPTIONS') { + add_header Access-Control-Allow-Origin * always; + add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always; + add_header Access-Control-Allow-Headers "Authorization, Content-Type" always; + add_header Access-Control-Max-Age 1728000; + add_header Content-Type 'text/plain charset=UTF-8'; + add_header Content-Length 0; + return 204; + } + proxy_pass http://backend:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/frontend/src/components/UserManagement.js b/frontend/src/components/UserManagement.js index 44c45db..706590a 100644 --- a/frontend/src/components/UserManagement.js +++ b/frontend/src/components/UserManagement.js @@ -26,7 +26,12 @@ function UserManagement({ user }) { setUsers(response.data.users || []); } catch (err) { console.error('Error loading users:', err); - setError('Failed to load users'); + const errorMessage = err.response?.data?.error || + err.response?.statusText || + err.message || + 'Failed to load users'; + const statusCode = err.response?.status; + setError(`Failed to load users${statusCode ? ` (${statusCode})` : ''}: ${errorMessage}`); } finally { setLoading(false); } From 6070d13d3fe1b6080adb9c25a4f8135fad0f135d Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:51:50 -0600 Subject: [PATCH 6/7] refactor: standardize request ID retrieval across analytics and API routes - Updated the method of obtaining the request ID in analytics.py and api.py to consistently use the request context. - Ensured that the request ID defaults to 'N/A' if not available, improving error handling and logging consistency across the application. --- backend/routes/analytics.py | 10 +++++++--- backend/routes/api.py | 2 +- backend/utils/logger.py | 8 +++++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/backend/routes/analytics.py b/backend/routes/analytics.py index c4dc9c0..2b1b8c8 100644 --- a/backend/routes/analytics.py +++ b/backend/routes/analytics.py @@ -24,7 +24,7 @@ def get_stats(): timestamp = get_utc_timestamp() ctx = get_request_context() - req_id = request_id if request_id else 'N/A' + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else 'N/A' stats = { 'user_count': query_helper.count_users(), @@ -54,13 +54,15 @@ def search(): query_helper = QueryHelper() search_time = get_utc_now() + ctx = get_request_context() + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else 'N/A' results = { 'query': search_term, 'users': [u.to_dict() for u in query_helper.search_users(search_term)], 'projects': [p.to_dict() for p in query_helper.search_projects(search_term)], 'search_time': search_time.isoformat(), - 'request_id': request_id if request_id else 'N/A' + 'request_id': req_id } log_user_action(user.id, 'analytics_search', {'term': search_term}) @@ -78,10 +80,12 @@ def get_user(user_id): return jsonify({'error': 'User not found'}), 404 fetched_at = get_utc_now() + ctx = get_request_context() + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else 'N/A' return jsonify({ 'user': user.to_dict(), 'fetched_at': fetched_at.isoformat(), - 'request_id': request_id if request_id else 'N/A' + 'request_id': req_id }) diff --git a/backend/routes/api.py b/backend/routes/api.py index 2e814e0..0062101 100644 --- a/backend/routes/api.py +++ b/backend/routes/api.py @@ -19,7 +19,7 @@ def get_users(): """Get all users""" # Access request context ctx = get_request_context() - req_id = request_id if request_id else 'N/A' + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else 'N/A' ip_address = get_request_metadata('ip_address', 'unknown') search = request.args.get('search', '') diff --git a/backend/utils/logger.py b/backend/utils/logger.py index dbbe8ad..e691349 100644 --- a/backend/utils/logger.py +++ b/backend/utils/logger.py @@ -50,7 +50,8 @@ def log_user_action(user_id, action, details=None): logger = logging.getLogger('projecthub') # Get request ID - req_id = request_id if request_id else "N/A" + ctx = get_request_context() + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else "N/A" duration = get_request_duration() duration_str = f" ({duration:.3f}s)" if duration else "" @@ -65,8 +66,8 @@ def log_login_attempt(username, password, success=False): logger = logging.getLogger('projecthub') # Get request ID - req_id = request_id if request_id else "N/A" ctx = get_request_context() + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else "N/A" ip_address = ctx.request.remote_addr if ctx and hasattr(ctx, 'request') and ctx.request else "unknown" status = "SUCCESS" if success else "FAILED" @@ -77,7 +78,8 @@ def log_api_request(user_id, endpoint, request_data): logger = logging.getLogger('projecthub') # Get request ID - req_id = request_id if request_id else "N/A" + ctx = get_request_context() + req_id = ctx.request_id if ctx and hasattr(ctx, 'request_id') else "N/A" duration = get_request_duration() duration_str = f" ({duration:.3f}s)" if duration else "" From 7fc1165e97f039504beef3cd86a17adb347bcbf1 Mon Sep 17 00:00:00 2001 From: Ryan Wakeham <85182216+cx-ryan-wakeham@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:55:52 -0600 Subject: [PATCH 7/7] feat: add health check and build readiness signal for frontend service - Implemented a health check in docker-compose.yml to ensure the frontend service is only started when the build is complete. - Updated docker-entrypoint.sh to create a readiness signal file after the build process, enhancing service dependency management. --- docker/docker-compose.yml | 9 ++++++++- frontend/docker-entrypoint.sh | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index d598362..e82178a 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -52,6 +52,12 @@ services: - frontend_build:/build-output depends_on: - backend + healthcheck: + test: ["CMD", "test", "-f", "/build-output/.ready", "-a", "-f", "/build-output/index.html"] + interval: 5s + timeout: 3s + retries: 30 + start_period: 10s networks: - app-network @@ -63,7 +69,8 @@ services: - ./nginx.conf:/etc/nginx/nginx.conf - frontend_build:/usr/share/nginx/html depends_on: - - frontend + frontend: + condition: service_healthy networks: - app-network diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh index 0be9458..d659e52 100644 --- a/frontend/docker-entrypoint.sh +++ b/frontend/docker-entrypoint.sh @@ -12,6 +12,10 @@ if [ -d "/build-output" ]; then rm -rf /build-output/* /build-output/.[!.]* /build-output/..?* 2>/dev/null || true cp -r /app/build/. /build-output/ echo "Build files copied successfully" + + # Create a ready file to signal that build is complete + touch /build-output/.ready + echo "Build ready signal created" else echo "Warning: /build-output directory not found, build files not copied to shared volume" fi