From f7874f4541ca472014c93cf4910642021fae4360 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Fri, 13 Jun 2025 23:21:45 +0000 Subject: [PATCH] feat(docs): clean up docs and make dev ex easier with variables --- README.md | 21 + docker-compose.yml | 118 +++-- .../DEPLOYMENT_SUMMARY.md | 0 .../QUEUE_IMPROVEMENTS.md | 0 docs/REVERSE_PROXY.md | 430 ++++++++++++++++++ TESTING.md => docs/TESTING.md | 0 WATCH_FOLDER.md => docs/WATCH_FOLDER.md | 0 frontend/vite.config.ts | 7 +- nginx.conf | 145 ++++++ run_all_tests.sh | 229 ---------- run_tests.sh | 83 ---- src/config.rs | 12 +- test_watch_folder.sh | 37 -- 13 files changed, 704 insertions(+), 378 deletions(-) rename DEPLOYMENT_SUMMARY.md => docs/DEPLOYMENT_SUMMARY.md (100%) rename QUEUE_IMPROVEMENTS.md => docs/QUEUE_IMPROVEMENTS.md (100%) create mode 100644 docs/REVERSE_PROXY.md rename TESTING.md => docs/TESTING.md (100%) rename WATCH_FOLDER.md => docs/WATCH_FOLDER.md (100%) create mode 100644 nginx.conf delete mode 100755 run_all_tests.sh delete mode 100755 run_tests.sh delete mode 100755 test_watch_folder.sh diff --git a/README.md b/README.md index a0eab3b..5ef62ef 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,25 @@ volumes: ### Environment Variables +#### Port Configuration + +Readur supports flexible port configuration: + +```bash +# Method 1: Specify full server address +SERVER_ADDRESS=0.0.0.0:3000 + +# Method 2: Use separate host and port (recommended) +SERVER_HOST=0.0.0.0 +SERVER_PORT=3000 + +# For development: Configure frontend port +CLIENT_PORT=5173 +BACKEND_PORT=8000 +``` + +#### Security Configuration + Create a `.env` file for your secrets: ```bash @@ -243,6 +262,8 @@ services: - "traefik.http.routers.readur.tls.certresolver=letsencrypt" ``` +> ๐Ÿ“˜ **For detailed reverse proxy configurations** including Apache, Caddy, custom ports, load balancing, and advanced scenarios, see [REVERSE_PROXY.md](./REVERSE_PROXY.md). + ### Health Checks Add health checks to your Docker configuration: diff --git a/docker-compose.yml b/docker-compose.yml index 863521e..0252534 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,34 +1,100 @@ -services: - readur: - build: . - ports: - - "8000:8000" - environment: - - DATABASE_URL=postgresql://readur:readur_password@postgres:5432/readur - - JWT_SECRET=your-super-secret-jwt-key-change-this-in-production - - UPLOAD_PATH=/app/uploads - - WATCH_FOLDER=/app/watch - - RUST_BACKTRACE=1 - volumes: - - uploads:/app/uploads - - watch:/app/watch - depends_on: - - postgres - restart: unless-stopped +version: '3.8' +services: postgres: - image: postgres:15 + image: postgres:16-alpine environment: - - POSTGRES_USER=readur - - POSTGRES_PASSWORD=readur_password - - POSTGRES_DB=readur + POSTGRES_USER: readur + POSTGRES_PASSWORD: readur + POSTGRES_DB: readur volumes: - postgres_data:/var/lib/postgresql/data ports: - - "5433:5432" - restart: unless-stopped + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U readur"] + interval: 10s + timeout: 5s + retries: 5 + + readur: + build: . + environment: + # Database configuration + DATABASE_URL: postgresql://readur:readur@postgres/readur + + # Server configuration - choose one of these methods: + # Method 1: Use SERVER_ADDRESS for full control + # SERVER_ADDRESS: 0.0.0.0:8080 + + # Method 2: Use SERVER_HOST and SERVER_PORT separately + SERVER_HOST: 0.0.0.0 + SERVER_PORT: 8080 + + # Security + JWT_SECRET: your-secret-key-change-this-in-production + + # File paths + UPLOAD_PATH: /app/uploads + WATCH_FOLDER: /app/watch + + # OCR configuration + OCR_LANGUAGE: eng + CONCURRENT_OCR_JOBS: 4 + OCR_TIMEOUT_SECONDS: 300 + MAX_FILE_SIZE_MB: 50 + + # Performance + MEMORY_LIMIT_MB: 512 + CPU_PRIORITY: normal + + # File watching + ALLOWED_FILE_TYPES: pdf,txt,doc,docx,png,jpg,jpeg + WATCH_INTERVAL_SECONDS: 30 + FILE_STABILITY_CHECK_MS: 1000 + MAX_FILE_AGE_HOURS: 24 + + ports: + # Map container port to host port + # Format: "host_port:container_port" + - "8080:8080" + + volumes: + # Persistent storage for uploads + - readur_uploads:/app/uploads + + # Watch folder - can be mapped to a host directory + - ./watch:/app/watch + + # Or use a named volume for watch folder + # - readur_watch:/app/watch + + depends_on: + postgres: + condition: service_healthy + + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Optional: Nginx reverse proxy example + nginx: + image: nginx:alpine + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + - ./ssl:/etc/nginx/ssl:ro + depends_on: + - readur + profiles: + - with-proxy volumes: - uploads: - watch: - postgres_data: \ No newline at end of file + postgres_data: + readur_uploads: + readur_watch: \ No newline at end of file diff --git a/DEPLOYMENT_SUMMARY.md b/docs/DEPLOYMENT_SUMMARY.md similarity index 100% rename from DEPLOYMENT_SUMMARY.md rename to docs/DEPLOYMENT_SUMMARY.md diff --git a/QUEUE_IMPROVEMENTS.md b/docs/QUEUE_IMPROVEMENTS.md similarity index 100% rename from QUEUE_IMPROVEMENTS.md rename to docs/QUEUE_IMPROVEMENTS.md diff --git a/docs/REVERSE_PROXY.md b/docs/REVERSE_PROXY.md new file mode 100644 index 0000000..ab2381f --- /dev/null +++ b/docs/REVERSE_PROXY.md @@ -0,0 +1,430 @@ +# Reverse Proxy Configuration Guide for Readur + +This guide covers various deployment scenarios for running Readur behind reverse proxies with configurable ports. + +## Table of Contents +- [Port Configuration](#port-configuration) +- [Docker Deployment](#docker-deployment) +- [Nginx Configuration](#nginx-configuration) +- [Traefik Configuration](#traefik-configuration) +- [Apache Configuration](#apache-configuration) +- [Caddy Configuration](#caddy-configuration) +- [Common Scenarios](#common-scenarios) +- [Troubleshooting](#troubleshooting) + +## Port Configuration + +Readur supports flexible port configuration through environment variables: + +### Server Port Configuration + +```bash +# Method 1: Full address specification +SERVER_ADDRESS=0.0.0.0:3000 + +# Method 2: Separate host and port (recommended) +SERVER_HOST=0.0.0.0 +SERVER_PORT=3000 +``` + +### Development Port Configuration + +For frontend development with Vite: + +```bash +# Backend API port +BACKEND_PORT=8000 + +# Frontend dev server port +CLIENT_PORT=5173 +``` + +## Docker Deployment + +### Basic Docker Run + +```bash +# Run on custom port 3000 +docker run -d \ + -e SERVER_PORT=3000 \ + -e DATABASE_URL=postgresql://user:pass@host/db \ + -e JWT_SECRET=your-secret-key \ + -p 3000:3000 \ + readur:latest +``` + +### Docker Compose with Custom Ports + +```yaml +version: '3.8' + +services: + readur: + image: readur:latest + environment: + SERVER_PORT: 3000 + DATABASE_URL: postgresql://readur:readur@postgres/readur + JWT_SECRET: ${JWT_SECRET} + ports: + - "3000:3000" +``` + +## Nginx Configuration + +### Basic Reverse Proxy + +```nginx +server { + listen 80; + server_name readur.example.com; + + location / { + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + 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; + + # Large file uploads for documents + client_max_body_size 100M; + + # Extended timeouts for OCR processing + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } +} +``` + +### SSL Configuration + +```nginx +server { + listen 443 ssl http2; + server_name readur.example.com; + + ssl_certificate /path/to/cert.pem; + ssl_certificate_key /path/to/key.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + location / { + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + 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 https; + + # WebSocket support (future feature) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} +``` + +### Subpath Configuration + +To serve Readur under a subpath like `/readur/`: + +```nginx +location /readur/ { + # Remove prefix when passing to backend + rewrite ^/readur/(.*) /$1 break; + + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + 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; + proxy_set_header X-Forwarded-Prefix /readur; +} +``` + +## Traefik Configuration + +### Docker Labels + +```yaml +version: '3.8' + +services: + readur: + image: readur:latest + environment: + SERVER_PORT: 3000 + labels: + - "traefik.enable=true" + - "traefik.http.routers.readur.rule=Host(`readur.example.com`)" + - "traefik.http.routers.readur.tls=true" + - "traefik.http.routers.readur.tls.certresolver=letsencrypt" + - "traefik.http.services.readur.loadbalancer.server.port=3000" + # Middleware for large uploads + - "traefik.http.middlewares.readur-upload.buffering.maxRequestBodyBytes=104857600" + - "traefik.http.routers.readur.middlewares=readur-upload" +``` + +### Static Configuration + +```yaml +# traefik.yml +http: + routers: + readur: + rule: "Host(`readur.example.com`)" + service: readur + tls: + certResolver: letsencrypt + middlewares: + - readur-headers + + services: + readur: + loadBalancer: + servers: + - url: "http://localhost:3000" + healthCheck: + path: /api/health + interval: 30s + + middlewares: + readur-headers: + headers: + customRequestHeaders: + X-Forwarded-Proto: https +``` + +## Apache Configuration + +### Basic Reverse Proxy + +```apache + + ServerName readur.example.com + + ProxyRequests Off + ProxyPreserveHost On + + ProxyPass / http://localhost:3000/ + ProxyPassReverse / http://localhost:3000/ + + # Large file uploads + LimitRequestBody 104857600 + + # Extended timeouts + ProxyTimeout 300 + +``` + +### SSL Configuration + +```apache + + ServerName readur.example.com + + SSLEngine on + SSLCertificateFile /path/to/cert.pem + SSLCertificateKeyFile /path/to/key.pem + + ProxyRequests Off + ProxyPreserveHost On + + ProxyPass / http://localhost:3000/ + ProxyPassReverse / http://localhost:3000/ + + RequestHeader set X-Forwarded-Proto "https" + +``` + +## Caddy Configuration + +### Caddyfile + +```caddy +readur.example.com { + reverse_proxy localhost:3000 { + header_up X-Real-IP {remote_host} + header_up X-Forwarded-Proto {scheme} + + # Health check + health_uri /api/health + health_interval 30s + + # Extended timeouts + transport http { + dial_timeout 10s + response_header_timeout 300s + } + } + + # Large file uploads + request_body { + max_size 100MB + } +} +``` + +## Common Scenarios + +### Multiple Instances with Load Balancing + +#### Nginx +```nginx +upstream readur_pool { + least_conn; + server readur1:3000 max_fails=3 fail_timeout=30s; + server readur2:3000 max_fails=3 fail_timeout=30s; + server readur3:3000 max_fails=3 fail_timeout=30s; +} + +server { + location / { + proxy_pass http://readur_pool; + # ... other proxy settings + } +} +``` + +#### Docker Compose Scale +```bash +# Scale to 3 instances +docker compose up -d --scale readur=3 +``` + +### Blue-Green Deployment + +```nginx +# nginx.conf +upstream readur_blue { + server blue:3000; +} + +upstream readur_green { + server green:3000; +} + +# Switch between blue and green +upstream readur_current { + server blue:3000; # Change to green:3000 for switch +} + +server { + location / { + proxy_pass http://readur_current; + } +} +``` + +### Rate Limiting + +```nginx +# Define rate limit zones +limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; +limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m; + +server { + # Apply to API endpoints + location /api/ { + limit_req zone=api burst=20 nodelay; + proxy_pass http://localhost:3000; + } + + # Stricter for auth + location /api/auth/ { + limit_req zone=auth burst=5 nodelay; + proxy_pass http://localhost:3000; + } +} +``` + +## Troubleshooting + +### Common Issues + +1. **502 Bad Gateway** + - Check if Readur is running on the configured port + - Verify `SERVER_PORT` environment variable + - Check container logs: `docker logs readur` + +2. **Large File Upload Failures** + - Increase `client_max_body_size` in nginx + - Adjust `MAX_FILE_SIZE_MB` in Readur config + - Check proxy timeout settings + +3. **WebSocket Connection Issues** (future feature) + - Ensure `proxy_http_version 1.1` is set + - Include Upgrade and Connection headers + +4. **CORS Errors** + - Readur includes CORS middleware + - Ensure `X-Forwarded-Proto` header is set correctly + - Check if frontend URL matches expected origin + +### Health Check Monitoring + +```bash +# Direct health check +curl http://localhost:3000/api/health + +# Through reverse proxy +curl https://readur.example.com/api/health + +# Expected response +{"status":"ok"} +``` + +### Debug Headers + +Add these to your reverse proxy for debugging: + +```nginx +add_header X-Proxy-Debug "nginx" always; +add_header X-Upstream-Addr $upstream_addr always; +add_header X-Upstream-Status $upstream_status always; +``` + +## Security Recommendations + +1. **Always use HTTPS** in production +2. **Implement rate limiting** to prevent abuse +3. **Set security headers**: + ```nginx + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + ``` + +4. **Restrict access** to health check endpoint if needed: + ```nginx + location /api/health { + allow 10.0.0.0/8; + deny all; + proxy_pass http://localhost:3000; + } + ``` + +5. **Use strong JWT secrets** and rotate them regularly +6. **Monitor access logs** for suspicious activity + +## Performance Optimization + +1. **Enable caching** for static assets: + ```nginx + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + proxy_pass http://localhost:3000; + expires 1y; + add_header Cache-Control "public, immutable"; + } + ``` + +2. **Use HTTP/2** for better performance +3. **Enable gzip compression**: + ```nginx + gzip on; + gzip_types text/plain text/css application/json application/javascript; + gzip_min_length 1000; + ``` + +4. **Configure connection pooling** for database +5. **Use CDN** for static assets in production \ No newline at end of file diff --git a/TESTING.md b/docs/TESTING.md similarity index 100% rename from TESTING.md rename to docs/TESTING.md diff --git a/WATCH_FOLDER.md b/docs/WATCH_FOLDER.md similarity index 100% rename from WATCH_FOLDER.md rename to docs/WATCH_FOLDER.md diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 7759654..cb2a8df 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,12 +1,17 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' +// Support environment variables for development +const BACKEND_PORT = process.env.BACKEND_PORT || '8000' +const CLIENT_PORT = process.env.CLIENT_PORT || '5173' + export default defineConfig({ plugins: [react()], server: { + port: parseInt(CLIENT_PORT), proxy: { '/api': { - target: 'http://localhost:8000', + target: `http://localhost:${BACKEND_PORT}`, changeOrigin: true, }, }, diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..234164c --- /dev/null +++ b/nginx.conf @@ -0,0 +1,145 @@ +events { + worker_connections 1024; +} + +http { + # Upstream configuration + upstream readur { + server readur:8080; + } + + # Rate limiting + limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; + limit_req_zone $binary_remote_addr zone=auth:10m rate=5r/m; + + server { + listen 80; + server_name localhost; + + # Redirect HTTP to HTTPS (uncomment in production) + # return 301 https://$server_name$request_uri; + + # For development without SSL + location / { + proxy_pass http://readur; + proxy_set_header Host $host; + 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; + } + } + + # HTTPS server configuration + server { + listen 443 ssl http2; + server_name localhost; + + # SSL configuration (update paths as needed) + ssl_certificate /etc/nginx/ssl/cert.pem; + ssl_certificate_key /etc/nginx/ssl/key.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Max upload size + client_max_body_size 100M; + client_body_timeout 300s; + + # Main application + location / { + proxy_pass http://readur; + proxy_set_header Host $host; + 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; + + # WebSocket support (if needed in future) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # Timeouts for long-running OCR operations + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + proxy_read_timeout 300s; + } + + # API rate limiting + location /api/ { + limit_req zone=api burst=20 nodelay; + + proxy_pass http://readur; + proxy_set_header Host $host; + 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; + } + + # Stricter rate limiting for auth endpoints + location /api/auth/ { + limit_req zone=auth burst=5 nodelay; + + proxy_pass http://readur; + proxy_set_header Host $host; + 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; + } + + # Health check endpoint (no rate limiting) + location /api/health { + proxy_pass http://readur; + proxy_set_header Host $host; + access_log off; + } + + # Static assets caching + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://readur; + proxy_set_header Host $host; + expires 1y; + add_header Cache-Control "public, immutable"; + } + } +} + +# Subpath example - serving readur under /readur/ +# server { +# listen 80; +# server_name example.com; +# +# location /readur/ { +# # Remove /readur prefix when passing to backend +# rewrite ^/readur/(.*) /$1 break; +# +# proxy_pass http://readur; +# proxy_set_header Host $host; +# 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; +# proxy_set_header X-Forwarded-Prefix /readur; +# } +# } + +# Multiple instances example +# upstream readur_pool { +# least_conn; +# server readur1:8080; +# server readur2:8080; +# server readur3:8080; +# } +# +# server { +# listen 80; +# +# location / { +# proxy_pass http://readur_pool; +# # ... rest of proxy configuration +# } +# } \ No newline at end of file diff --git a/run_all_tests.sh b/run_all_tests.sh deleted file mode 100755 index a5ed68c..0000000 --- a/run_all_tests.sh +++ /dev/null @@ -1,229 +0,0 @@ -#!/bin/bash - -# Readur - Complete Test Suite Runner -# This script runs all unit tests and integration tests for the Readur project - -set -e - -echo "๐Ÿงช Readur Complete Test Suite" -echo "==============================" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Function to print colored output -print_step() { - echo -e "${BLUE}๐Ÿ“‹ $1${NC}" -} - -print_success() { - echo -e "${GREEN}โœ… $1${NC}" -} - -print_warning() { - echo -e "${YELLOW}โš ๏ธ $1${NC}" -} - -print_error() { - echo -e "${RED}โŒ $1${NC}" -} - -# Check if PostgreSQL is running (for integration tests) -check_postgres() { - if ! command -v psql >/dev/null 2>&1; then - print_warning "PostgreSQL not found. Integration tests may fail." - return 1 - fi - - if ! pg_isready >/dev/null 2>&1; then - print_warning "PostgreSQL is not running. Integration tests may fail." - return 1 - fi - - return 0 -} - -# Backend Unit Tests -run_backend_unit_tests() { - print_step "Running Backend Unit Tests" - - if cargo test --lib; then - print_success "Backend unit tests passed" - return 0 - else - print_error "Backend unit tests failed" - return 1 - fi -} - -# Backend Integration Tests -run_backend_integration_tests() { - print_step "Running Backend Integration Tests" - - if ! check_postgres; then - print_warning "Skipping integration tests - PostgreSQL not available" - return 0 - fi - - # Check if server is running - if ! curl -s http://localhost:8000/api/health >/dev/null 2>&1; then - print_warning "Server not running at localhost:8000" - print_warning "Start server with: cargo run" - print_warning "Skipping integration tests" - return 0 - fi - - if RUST_BACKTRACE=1 cargo test --test integration_tests; then - print_success "Backend integration tests passed" - return 0 - else - print_error "Backend integration tests failed" - return 1 - fi -} - -# Frontend Tests -run_frontend_tests() { - print_step "Running Frontend Tests" - - if [ ! -d "frontend" ]; then - print_error "Frontend directory not found" - return 1 - fi - - cd frontend - - if [ ! -f "package.json" ]; then - print_error "package.json not found in frontend directory" - cd .. - return 1 - fi - - # Install dependencies if node_modules doesn't exist - if [ ! -d "node_modules" ]; then - print_step "Installing frontend dependencies..." - npm install - fi - - if npm test -- --run; then - print_success "Frontend tests completed" - cd .. - return 0 - else - print_warning "Frontend tests had failures (this is expected - work in progress)" - cd .. - return 0 # Don't fail the overall script for frontend test issues - fi -} - -# Test Coverage (optional) -generate_coverage() { - print_step "Generating Test Coverage (optional)" - - # Backend coverage - if command -v cargo-tarpaulin >/dev/null 2>&1; then - print_step "Generating backend coverage..." - cargo tarpaulin --out Html --output-dir coverage/ >/dev/null 2>&1 || true - print_success "Backend coverage generated in coverage/" - else - print_warning "cargo-tarpaulin not installed. Run: cargo install cargo-tarpaulin" - fi - - # Frontend coverage - if [ -d "frontend" ]; then - cd frontend - if npm run test:coverage >/dev/null 2>&1; then - print_success "Frontend coverage generated in frontend/coverage/" - fi - cd .. - fi -} - -# Main execution -main() { - echo "Starting test suite at $(date)" - echo "" - - # Track overall success - overall_success=true - - # Run backend unit tests - if ! run_backend_unit_tests; then - overall_success=false - fi - - echo "" - - # Run backend integration tests - if ! run_backend_integration_tests; then - overall_success=false - fi - - echo "" - - # Run frontend tests (don't fail overall on frontend issues) - run_frontend_tests - - echo "" - - # Generate coverage if requested - if [ "$1" = "--coverage" ]; then - generate_coverage - echo "" - fi - - # Summary - echo "==============================" - if [ "$overall_success" = true ]; then - print_success "Test Suite Completed Successfully!" - echo "" - echo "๐Ÿ“Š Test Summary:" - echo " โœ… Backend Unit Tests: PASSED" - echo " โœ… Backend Integration Tests: PASSED" - echo " ๐Ÿ”„ Frontend Tests: IN PROGRESS (28/75 passing)" - echo "" - echo "๐ŸŽ‰ All critical backend tests are passing!" - exit 0 - else - print_error "Test Suite Failed" - echo "" - echo "โŒ Some backend tests failed. Check output above for details." - echo "" - echo "๐Ÿ’ก Troubleshooting tips:" - echo " โ€ข Ensure PostgreSQL is running" - echo " โ€ข Check DATABASE_URL environment variable" - echo " โ€ข Start server: cargo run" - echo " โ€ข Run with debug: RUST_BACKTRACE=1 cargo test" - exit 1 - fi -} - -# Handle script arguments -case "$1" in - --help|-h) - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " --coverage Generate test coverage reports" - echo " --help, -h Show this help message" - echo "" - echo "Examples:" - echo " $0 # Run all tests" - echo " $0 --coverage # Run all tests and generate coverage" - echo "" - echo "Prerequisites:" - echo " โ€ข Rust toolchain" - echo " โ€ข PostgreSQL (for integration tests)" - echo " โ€ข Node.js (for frontend tests)" - echo "" - echo "For detailed testing documentation, see TESTING.md" - exit 0 - ;; - *) - main "$@" - ;; -esac diff --git a/run_tests.sh b/run_tests.sh deleted file mode 100755 index 80517ee..0000000 --- a/run_tests.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash - -# Test runner script for Readur -# This script runs tests in different modes to handle dependencies - -echo "๐Ÿงช Readur Test Runner" -echo "====================" - -# Function to run tests with specific configuration -run_tests() { - local mode="$1" - local flags="$2" - local description="$3" - - echo "" - echo "๐Ÿ“‹ Running $description" - echo "Command: cargo test $flags" - echo "-------------------------------------------" - - if cargo test $flags; then - echo "โœ… $description: PASSED" - else - echo "โŒ $description: FAILED" - return 1 - fi -} - -# Check if Docker is available for integration tests -check_docker() { - if command -v docker &> /dev/null && docker info &> /dev/null; then - echo "๐Ÿณ Docker is available - integration tests can run" - return 0 - else - echo "โš ๏ธ Docker not available - skipping integration tests" - return 1 - fi -} - -# Main test execution -echo "Starting test execution..." - -# 1. Run unit tests without OCR dependencies (fastest) -run_tests "unit" "--lib --no-default-features -- --skip database --skip integration" "Unit tests (no OCR/DB dependencies)" -unit_result=$? - -# 2. Run unit tests with OCR dependencies (requires tesseract) -if command -v tesseract &> /dev/null; then - echo "๐Ÿ“ท Tesseract OCR available - running OCR tests" - run_tests "ocr" "--lib --features ocr -- --skip database --skip integration" "Unit tests with OCR support" - ocr_result=$? -else - echo "โš ๏ธ Tesseract not available - skipping OCR tests" - echo " Install with: sudo apt-get install tesseract-ocr tesseract-ocr-eng" - ocr_result=0 # Don't fail if tesseract isn't available -fi - -# 3. Run integration tests (requires Docker for PostgreSQL) -if check_docker; then - run_tests "integration" "--lib --features ocr" "Integration tests (requires Docker/PostgreSQL)" - integration_result=$? -else - integration_result=0 # Don't fail if Docker isn't available -fi - -# Summary -echo "" -echo "๐Ÿ“Š Test Summary" -echo "===============" -echo "Unit tests (basic): $([ $unit_result -eq 0 ] && echo "โœ… PASSED" || echo "โŒ FAILED")" -echo "Unit tests (with OCR): $([ $ocr_result -eq 0 ] && echo "โœ… PASSED" || echo "โš ๏ธ SKIPPED")" -echo "Integration tests: $([ $integration_result -eq 0 ] && echo "โœ… PASSED" || echo "โš ๏ธ SKIPPED")" - -# Exit with appropriate code -if [ $unit_result -eq 0 ]; then - echo "" - echo "๐ŸŽ‰ Core functionality tests passed!" - echo "Your code changes are working correctly." - exit 0 -else - echo "" - echo "๐Ÿ’ฅ Some tests failed. Please check the output above." - exit 1 -fi \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index a2a2303..9af6a09 100644 --- a/src/config.rs +++ b/src/config.rs @@ -31,8 +31,16 @@ impl Config { Ok(Config { database_url: env::var("DATABASE_URL") .unwrap_or_else(|_| "postgresql://readur:readur@localhost/readur".to_string()), - server_address: env::var("SERVER_ADDRESS") - .unwrap_or_else(|_| "0.0.0.0:8000".to_string()), + server_address: { + // Support both SERVER_ADDRESS (full address) and SERVER_PORT (just port) + if let Ok(addr) = env::var("SERVER_ADDRESS") { + addr + } else { + let host = env::var("SERVER_HOST").unwrap_or_else(|_| "0.0.0.0".to_string()); + let port = env::var("SERVER_PORT").unwrap_or_else(|_| "8000".to_string()); + format!("{}:{}", host, port) + } + }, jwt_secret: env::var("JWT_SECRET") .unwrap_or_else(|_| "your-secret-key".to_string()), upload_path: env::var("UPLOAD_PATH") diff --git a/test_watch_folder.sh b/test_watch_folder.sh deleted file mode 100755 index 880c1ec..0000000 --- a/test_watch_folder.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# Test script for watch folder functionality -echo "Testing watch folder functionality..." - -# Create a test watch folder if it doesn't exist -mkdir -p ./watch - -echo "Creating test files in watch folder..." - -# Create a test text file -echo "This is a test document for OCR processing." > ./watch/test_document.txt - -# Create a test PDF file (mock content) -echo "%PDF-1.4 Mock PDF for testing" > ./watch/test_document.pdf - -# Create a test image file (mock content) -echo "Mock PNG image content" > ./watch/test_image.png - -echo "Test files created in ./watch/ folder:" -ls -la ./watch/ - -echo "" -echo "Watch folder setup complete!" -echo "You can now:" -echo "1. Start the readur application" -echo "2. Copy OCR-able files to the ./watch/ folder" -echo "3. Monitor the logs to see files being processed" -echo "" -echo "Supported file types: PDF, PNG, JPG, JPEG, TIFF, BMP, TXT, DOC, DOCX" -echo "" -echo "Environment variables for configuration:" -echo "- WATCH_FOLDER: Path to watch folder (default: ./watch)" -echo "- WATCH_INTERVAL_SECONDS: Polling interval (default: 30)" -echo "- FILE_STABILITY_CHECK_MS: File stability check time (default: 500)" -echo "- MAX_FILE_AGE_HOURS: Skip files older than this (default: none)" -echo "- FORCE_POLLING_WATCH: Force polling mode (default: auto-detect)" \ No newline at end of file