feat(docs): clean up docs and make dev ex easier with variables
This commit is contained in:
parent
68f5da509b
commit
f7874f4541
21
README.md
21
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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
postgres_data:
|
||||
readur_uploads:
|
||||
readur_watch:
|
||||
|
|
@ -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
|
||||
<VirtualHost *:80>
|
||||
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
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
### SSL Configuration
|
||||
|
||||
```apache
|
||||
<VirtualHost *:443>
|
||||
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"
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
## 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
|
||||
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
# }
|
||||
# }
|
||||
229
run_all_tests.sh
229
run_all_tests.sh
|
|
@ -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
|
||||
83
run_tests.sh
83
run_tests.sh
|
|
@ -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
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
Loading…
Reference in New Issue