Forráskód Böngészése

feat: Add complete Docker containerization for development and production

Implement comprehensive Docker setup for Market Data Service with support
for both local development and production deployment.

Features:
- Multi-stage Dockerfile with optimized production builds
- Development setup with live code reload (nodemon)
- Docker Compose configurations for dev and prod environments
- PostgreSQL database container with automatic initialization
- Nginx reverse proxy with WebSocket support for Socket.io
- Automatic database migrations on container startup
- Health checks for all services
- Data persistence via Docker volumes
- SSL/TLS support in production configuration
- Complete documentation in DOCKER.md

Files added:
- Dockerfile: Multi-stage build (dependencies + production)
- docker-compose.yml: Development environment
- docker-compose.prod.yml: Production environment
- nginx/nginx.conf: Development Nginx config (HTTP + WebSocket)
- nginx/nginx.prod.conf: Production Nginx config (HTTPS + SSL)
- docker/entrypoint.sh: API container entrypoint with migrations
- docker/wait-for-db.sh: Database readiness check
- docker/init-db.sh: Database initialization script
- .dockerignore: Docker build exclusions
- DOCKER.md: Complete containerization documentation

Files modified:
- .gitignore: Added Docker-related entries

This enables zero-dependency local development (only Docker Desktop required)
and production-ready containerized deployment with proper security, scaling,
and data persistence.
Hussain Afzal 8 hónapja
szülő
commit
7c642d6730
10 módosított fájl, 1202 hozzáadás és 0 törlés
  1. 22 0
      .gitignore
  2. 537 0
      DOCKER.md
  3. 77 0
      Dockerfile
  4. 97 0
      docker-compose.prod.yml
  5. 90 0
      docker-compose.yml
  6. 45 0
      docker/entrypoint.sh
  7. 27 0
      docker/init-db.sh
  8. 29 0
      docker/wait-for-db.sh
  9. 114 0
      nginx/nginx.conf
  10. 164 0
      nginx/nginx.prod.conf

+ 22 - 0
.gitignore

@@ -97,3 +97,25 @@ temp/
 
 # OS generated files
 Thumbs.db
+
+# Docker
+.docker/
+docker-compose.override.yml
+*.dockerignore
+
+# Docker volumes (if using local volumes)
+docker-volumes/
+volumes/
+
+# SSL certificates (should not be committed)
+ssl/
+*.pem
+*.key
+*.crt
+*.cert
+
+# Backup files
+backups/
+*.sql.gz
+*.sql
+backup_*.sql

+ 537 - 0
DOCKER.md

@@ -0,0 +1,537 @@
+# Docker Containerization Guide
+
+Complete guide for running Market Data Service in Docker containers for both development and production environments.
+
+## Table of Contents
+
+- [Prerequisites](#prerequisites)
+- [Quick Start](#quick-start)
+- [Development Setup](#development-setup)
+- [Production Setup](#production-setup)
+- [Configuration](#configuration)
+- [Common Operations](#common-operations)
+- [Troubleshooting](#troubleshooting)
+- [Backup and Restore](#backup-and-restore)
+
+## Prerequisites
+
+- **Docker Desktop** (Mac/Windows) or **Docker Engine** (Linux)
+- **Docker Compose** v2.0+ (included with Docker Desktop)
+- **Git** (for cloning repository)
+
+No other dependencies required! Everything runs in containers.
+
+## Quick Start
+
+### Development Environment
+
+```bash
+# 1. Clone the repository
+git clone <repository-url>
+cd market-data-service
+
+# 2. Copy environment template
+cp .env.example .env
+
+# 3. Edit .env file with your settings (optional for development)
+# Default values work for local development
+
+# 4. Start all services
+docker-compose up -d
+
+# 5. Check service status
+docker-compose ps
+
+# 6. View logs
+docker-compose logs -f api
+```
+
+The API will be available at:
+- **HTTP**: http://localhost
+- **API Endpoints**: http://localhost/api/*
+- **Health Check**: http://localhost/health
+- **WebSocket**: ws://localhost/socket.io/
+
+### Production Environment
+
+```bash
+# 1. Set up environment variables
+cp .env.example .env
+# Edit .env with production values
+
+# 2. Set up SSL certificates (if using HTTPS)
+# Place certificates in ./ssl/certs/ and ./ssl/private/
+# Or update SSL_CERT_PATH and SSL_KEY_PATH in docker-compose.prod.yml
+
+# 3. Start production services
+docker-compose -f docker-compose.prod.yml up -d
+
+# 4. Check status
+docker-compose -f docker-compose.prod.yml ps
+```
+
+## Development Setup
+
+### Architecture
+
+The development environment consists of three services:
+
+1. **API Service** (`api`)
+   - Node.js/Express application
+   - Live code reload with volume mounts
+   - Runs on port 3000 (internal)
+   - Accessible via Nginx on port 80
+
+2. **Database Service** (`db`)
+   - PostgreSQL 15
+   - Exposed on port 5432 (for local tools)
+   - Data persisted in Docker volume
+
+3. **Nginx Service** (`nginx`)
+   - Reverse proxy
+   - WebSocket support for Socket.io
+   - Exposed on port 80
+
+### Starting Development Environment
+
+```bash
+# Start all services in detached mode
+docker-compose up -d
+
+# Start with logs visible
+docker-compose up
+
+# Rebuild containers after code changes
+docker-compose up -d --build
+```
+
+### Accessing Services
+
+- **API**: http://localhost
+- **Database**: localhost:5432
+- **API Direct**: http://localhost:3000 (if port mapping enabled)
+
+### Development Workflow
+
+1. **Make code changes** in `src/` directory
+2. **Changes are automatically reloaded** (nodemon watches for changes)
+3. **View logs**: `docker-compose logs -f api`
+4. **Restart service**: `docker-compose restart api`
+
+### Database Migrations
+
+Migrations run automatically on container startup. To run manually:
+
+```bash
+# Run migrations
+docker-compose exec api npx sequelize-cli db:migrate
+
+# Rollback last migration
+docker-compose exec api npx sequelize-cli db:migrate:undo
+
+# Check migration status
+docker-compose exec api npx sequelize-cli db:migrate:status
+```
+
+### Accessing Database
+
+```bash
+# Connect to PostgreSQL
+docker-compose exec db psql -U postgres -d financial_data
+
+# Run SQL commands
+docker-compose exec db psql -U postgres -d financial_data -c "SELECT * FROM symbols LIMIT 10;"
+
+# List tables
+docker-compose exec db psql -U postgres -d financial_data -c "\dt"
+```
+
+## Production Setup
+
+### Architecture
+
+Production environment uses optimized settings:
+
+- **No volume mounts** (code baked into image)
+- **Multi-stage builds** for smaller images
+- **Health checks** for all services
+- **SSL/TLS** support via Nginx
+- **Restart policies** for high availability
+
+### Prerequisites for Production
+
+1. **Environment Variables**
+   ```bash
+   # Set strong passwords and secrets
+   DB_PASSWORD=<strong_password>
+   JWT_SECRET=<strong_random_secret>
+   CORS_ORIGIN=https://your-domain.com
+   ```
+
+2. **SSL Certificates** (for HTTPS)
+   ```bash
+   # Option 1: Use Let's Encrypt (recommended)
+   # Certificates will be in /etc/letsencrypt/live/your-domain.com/
+   
+   # Option 2: Place certificates manually
+   mkdir -p ssl/certs ssl/private
+   # Copy fullchain.pem to ssl/certs/
+   # Copy privkey.pem to ssl/private/
+   ```
+
+3. **Update Nginx Configuration**
+   - Edit `nginx/nginx.prod.conf`
+   - Update SSL certificate paths
+   - Update `server_name` if using domain names
+
+### Starting Production Environment
+
+```bash
+# Build production images
+docker-compose -f docker-compose.prod.yml build
+
+# Start services
+docker-compose -f docker-compose.prod.yml up -d
+
+# Check health status
+docker-compose -f docker-compose.prod.yml ps
+```
+
+### Production Features
+
+- **Automatic migrations** on startup
+- **Health checks** for service monitoring
+- **SSL/TLS** encryption
+- **Security headers** (HSTS, X-Frame-Options, etc.)
+- **Rate limiting** (configurable in nginx.prod.conf)
+- **Data persistence** via Docker volumes
+
+## Configuration
+
+### Environment Variables
+
+Key environment variables (see `.env.example` for complete list):
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `DB_HOST` | Database host | `db` (Docker) or `localhost` |
+| `DB_PORT` | Database port | `5432` |
+| `DB_NAME` | Database name | `financial_data` |
+| `DB_USER` | Database user | `postgres` |
+| `DB_PASSWORD` | Database password | **Required** |
+| `PORT` | API port | `3000` |
+| `NODE_ENV` | Environment | `development` or `production` |
+| `CORS_ORIGIN` | Allowed origins | `*` |
+| `JWT_SECRET` | JWT secret key | **Required** |
+| `LOG_LEVEL` | Logging level | `debug` (dev) or `info` (prod) |
+
+### Nginx Configuration
+
+- **Development**: `nginx/nginx.conf` (HTTP only)
+- **Production**: `nginx/nginx.prod.conf` (HTTPS with SSL)
+
+Key features:
+- WebSocket proxy for Socket.io
+- API endpoint routing
+- Health check endpoint
+- Security headers (production)
+- Rate limiting (production)
+
+### Database Configuration
+
+Database is automatically initialized with:
+- Database: `financial_data`
+- User: `postgres` (or from `DB_USER`)
+- Migrations run on API container startup
+
+## Common Operations
+
+### Viewing Logs
+
+```bash
+# All services
+docker-compose logs -f
+
+# Specific service
+docker-compose logs -f api
+docker-compose logs -f db
+docker-compose logs -f nginx
+
+# Last 100 lines
+docker-compose logs --tail=100 api
+```
+
+### Restarting Services
+
+```bash
+# Restart all services
+docker-compose restart
+
+# Restart specific service
+docker-compose restart api
+
+# Stop all services
+docker-compose down
+
+# Stop and remove volumes (WARNING: deletes data)
+docker-compose down -v
+```
+
+### Accessing Containers
+
+```bash
+# Execute command in API container
+docker-compose exec api sh
+
+# Execute command in database container
+docker-compose exec db sh
+
+# Run Node.js commands
+docker-compose exec api node -v
+docker-compose exec api npm list
+```
+
+### Updating Application
+
+```bash
+# 1. Pull latest code
+git pull
+
+# 2. Rebuild containers
+docker-compose build
+
+# 3. Restart services (migrations run automatically)
+docker-compose up -d
+
+# Or for production
+docker-compose -f docker-compose.prod.yml build
+docker-compose -f docker-compose.prod.yml up -d
+```
+
+### Health Checks
+
+```bash
+# Check container health
+docker-compose ps
+
+# Test API health endpoint
+curl http://localhost/health
+
+# Test database connection
+docker-compose exec db pg_isready -U postgres
+```
+
+## Troubleshooting
+
+### Database Connection Issues
+
+**Problem**: API can't connect to database
+
+**Solutions**:
+```bash
+# Check database is running
+docker-compose ps db
+
+# Check database logs
+docker-compose logs db
+
+# Test database connection manually
+docker-compose exec db psql -U postgres -d financial_data
+
+# Verify environment variables
+docker-compose exec api env | grep DB_
+```
+
+### Migration Failures
+
+**Problem**: Migrations fail on startup
+
+**Solutions**:
+```bash
+# Check migration logs
+docker-compose logs api | grep -i migration
+
+# Run migrations manually
+docker-compose exec api npx sequelize-cli db:migrate
+
+# Check migration status
+docker-compose exec api npx sequelize-cli db:migrate:status
+```
+
+### WebSocket Connection Issues
+
+**Problem**: WebSocket connections fail through Nginx
+
+**Solutions**:
+1. Verify Nginx configuration includes WebSocket upgrade headers
+2. Check Nginx logs: `docker-compose logs nginx`
+3. Test direct connection: `ws://localhost:3000/socket.io/`
+4. Verify Socket.io transport is set to 'websocket' only
+
+### Port Conflicts
+
+**Problem**: Port already in use
+
+**Solutions**:
+```bash
+# Check what's using the port
+lsof -i :80
+lsof -i :5432
+
+# Change ports in docker-compose.yml
+# Update PORT and DB_PORT environment variables
+```
+
+### Container Won't Start
+
+**Problem**: Container exits immediately
+
+**Solutions**:
+```bash
+# Check exit code
+docker-compose ps
+
+# View detailed logs
+docker-compose logs api
+
+# Check container status
+docker ps -a
+
+# Try starting without detached mode
+docker-compose up api
+```
+
+### Permission Issues
+
+**Problem**: Permission denied errors
+
+**Solutions**:
+```bash
+# Fix script permissions
+chmod +x docker/*.sh
+
+# Check file ownership
+ls -la docker/
+
+# Rebuild containers
+docker-compose build --no-cache
+```
+
+## Backup and Restore
+
+### Database Backup
+
+```bash
+# Create backup
+docker-compose exec db pg_dump -U postgres financial_data > backup_$(date +%Y%m%d_%H%M%S).sql
+
+# Or using docker directly
+docker exec market-data-db pg_dump -U postgres financial_data > backup.sql
+```
+
+### Database Restore
+
+```bash
+# Restore from backup
+docker-compose exec -T db psql -U postgres financial_data < backup.sql
+
+# Or using docker directly
+docker exec -i market-data-db psql -U postgres financial_data < backup.sql
+```
+
+### Volume Backup
+
+```bash
+# Backup database volume
+docker run --rm -v market_data_db_data:/data -v $(pwd):/backup alpine tar czf /backup/db_backup.tar.gz /data
+
+# Restore database volume
+docker run --rm -v market_data_db_data:/data -v $(pwd):/backup alpine tar xzf /backup/db_backup.tar.gz -C /
+```
+
+### Automated Backups
+
+Create a cron job or scheduled task:
+
+```bash
+# Daily backup script
+#!/bin/bash
+BACKUP_DIR="./backups"
+DATE=$(date +%Y%m%d_%H%M%S)
+mkdir -p $BACKUP_DIR
+docker-compose exec -T db pg_dump -U postgres financial_data | gzip > $BACKUP_DIR/backup_$DATE.sql.gz
+# Keep only last 30 days
+find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +30 -delete
+```
+
+## MT5 EA Integration
+
+### Development
+
+Update MT5 EA settings:
+- `ApiBaseUrl`: `http://localhost` or `http://localhost:3000`
+
+### Production
+
+Update MT5 EA settings:
+- `ApiBaseUrl`: `https://your-domain.com`
+- Ensure SSL certificate is valid
+- WebSocket connections use `wss://` protocol
+
+## Performance Tuning
+
+### Database Optimization
+
+```bash
+# Increase shared buffers (edit postgresql.conf in container)
+# Or use environment variables in docker-compose.yml
+```
+
+### Nginx Optimization
+
+- Adjust `worker_processes` in nginx.conf
+- Tune `worker_connections` based on expected load
+- Enable caching for static assets (if any)
+
+### Container Resources
+
+Limit resources in `docker-compose.prod.yml`:
+
+```yaml
+services:
+  api:
+    deploy:
+      resources:
+        limits:
+          cpus: '2'
+          memory: 2G
+        reservations:
+          cpus: '1'
+          memory: 1G
+```
+
+## Security Best Practices
+
+1. **Change Default Passwords**: Always set strong `DB_PASSWORD` and `JWT_SECRET`
+2. **Use HTTPS in Production**: Configure SSL certificates
+3. **Limit CORS Origins**: Set specific `CORS_ORIGIN` in production
+4. **Regular Updates**: Keep Docker images updated
+5. **Backup Regularly**: Automate database backups
+6. **Monitor Logs**: Set up log monitoring and alerting
+7. **Use Secrets**: Consider Docker secrets for sensitive data
+
+## Additional Resources
+
+- [Docker Documentation](https://docs.docker.com/)
+- [Docker Compose Documentation](https://docs.docker.com/compose/)
+- [PostgreSQL Docker Image](https://hub.docker.com/_/postgres)
+- [Nginx Documentation](https://nginx.org/en/docs/)
+
+## Support
+
+For issues or questions:
+1. Check logs: `docker-compose logs`
+2. Review this documentation
+3. Check GitHub issues
+4. Contact development team
+

+ 77 - 0
Dockerfile

@@ -0,0 +1,77 @@
+# Multi-stage Dockerfile for Market Data Service API
+# Stage 1: Dependencies installation (for development)
+FROM node:18-alpine AS dependencies
+
+WORKDIR /app
+
+# Copy package files
+COPY package*.json ./
+
+# Install all dependencies (including dev dependencies for build tools)
+RUN npm ci
+
+# Copy application code and scripts (needed for development)
+COPY . .
+
+# Create logs directory
+RUN mkdir -p logs
+
+# Copy entrypoint and wait scripts
+COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
+COPY docker/wait-for-db.sh /usr/local/bin/wait-for-db.sh
+RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/wait-for-db.sh
+
+# Install PostgreSQL client for wait script (pg_isready)
+RUN apk add --no-cache postgresql-client
+
+# Expose port
+EXPOSE 3000
+
+# Default command (can be overridden in docker-compose)
+CMD ["npm", "start"]
+
+# Stage 2: Production build
+FROM node:18-alpine AS production
+
+WORKDIR /app
+
+# Copy package files
+COPY package*.json ./
+
+# Install only production dependencies
+RUN npm ci --only=production && npm cache clean --force
+
+# Copy application code
+COPY . .
+
+# Create logs directory
+RUN mkdir -p logs
+
+# Copy entrypoint script
+COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh
+COPY docker/wait-for-db.sh /usr/local/bin/wait-for-db.sh
+RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/wait-for-db.sh
+
+# Install PostgreSQL client for wait script
+RUN apk add --no-cache postgresql-client
+
+# Set non-root user for security
+RUN addgroup -g 1001 -S nodejs && \
+    adduser -S nodejs -u 1001 && \
+    chown -R nodejs:nodejs /app
+
+USER nodejs
+
+# Expose port
+EXPOSE 3000
+
+# Health check
+HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
+  CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
+
+# Use entrypoint script
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
+
+# Default command
+CMD ["npm", "start"]
+

+ 97 - 0
docker-compose.prod.yml

@@ -0,0 +1,97 @@
+version: '3.8'
+
+services:
+  # PostgreSQL Database Service (Production)
+  db:
+    image: postgres:15-alpine
+    container_name: market-data-db-prod
+    environment:
+      POSTGRES_USER: ${DB_USER:-postgres}
+      POSTGRES_PASSWORD: ${DB_PASSWORD}
+      POSTGRES_DB: ${DB_NAME:-financial_data}
+      PGDATA: /var/lib/postgresql/data/pgdata
+    volumes:
+      - market_data_db_data_prod:/var/lib/postgresql/data
+      - ./docker/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
+    # No exposed ports in production (internal only)
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-financial_data}"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+    networks:
+      - market-data-network
+    restart: unless-stopped
+    # Production security: run as non-root
+    user: "999:999"
+
+  # Node.js API Service (Production)
+  api:
+    build:
+      context: .
+      dockerfile: Dockerfile
+      target: production
+    container_name: market-data-api-prod
+    environment:
+      - NODE_ENV=production
+      - PORT=3000
+      - DB_HOST=db
+      - DB_PORT=5432
+      - DB_NAME=${DB_NAME:-financial_data}
+      - DB_USER=${DB_USER:-postgres}
+      - DB_PASSWORD=${DB_PASSWORD}
+      - CORS_ORIGIN=${CORS_ORIGIN:-*}
+      - JWT_SECRET=${JWT_SECRET}
+      - LOG_LEVEL=${LOG_LEVEL:-info}
+    # No volume mounts in production (code is baked into image)
+    # Optional: mount logs volume for persistence
+    volumes:
+      - market_data_logs_prod:/app/logs
+    # No exposed ports (accessed only through nginx)
+    depends_on:
+      db:
+        condition: service_healthy
+    networks:
+      - market-data-network
+    restart: unless-stopped
+    healthcheck:
+      test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
+      interval: 30s
+      timeout: 10s
+      start_period: 40s
+      retries: 3
+
+  # Nginx Reverse Proxy (Production)
+  nginx:
+    image: nginx:alpine
+    container_name: market-data-nginx-prod
+    ports:
+      - "80:80"
+      - "443:443"
+    volumes:
+      - ./nginx/nginx.prod.conf:/etc/nginx/nginx.conf:ro
+      # SSL certificates (mount your certbot certificates here)
+      - ${SSL_CERT_PATH:-./ssl/certs}:/etc/nginx/ssl/certs:ro
+      - ${SSL_KEY_PATH:-./ssl/private}:/etc/nginx/ssl/private:ro
+    depends_on:
+      api:
+        condition: service_healthy
+    networks:
+      - market-data-network
+    restart: unless-stopped
+    healthcheck:
+      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+
+volumes:
+  market_data_db_data_prod:
+    driver: local
+  market_data_logs_prod:
+    driver: local
+
+networks:
+  market-data-network:
+    driver: bridge
+

+ 90 - 0
docker-compose.yml

@@ -0,0 +1,90 @@
+version: '3.8'
+
+services:
+  # PostgreSQL Database Service
+  db:
+    image: postgres:15-alpine
+    container_name: market-data-db
+    environment:
+      POSTGRES_USER: ${DB_USER:-postgres}
+      POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
+      POSTGRES_DB: ${DB_NAME:-financial_data}
+      PGDATA: /var/lib/postgresql/data/pgdata
+    volumes:
+      - market_data_db_data:/var/lib/postgresql/data
+      - ./docker/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
+    ports:
+      - "${DB_PORT:-5432}:5432"
+    healthcheck:
+      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-financial_data}"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+    networks:
+      - market-data-network
+    restart: unless-stopped
+
+  # Node.js API Service
+  api:
+    build:
+      context: .
+      dockerfile: Dockerfile
+      target: dependencies
+    container_name: market-data-api
+    environment:
+      - NODE_ENV=${NODE_ENV:-development}
+      - PORT=${PORT:-3000}
+      - DB_HOST=db
+      - DB_PORT=5432
+      - DB_NAME=${DB_NAME:-financial_data}
+      - DB_USER=${DB_USER:-postgres}
+      - DB_PASSWORD=${DB_PASSWORD:-postgres}
+      - CORS_ORIGIN=${CORS_ORIGIN:-*}
+      - JWT_SECRET=${JWT_SECRET:-change-me-in-production}
+      - LOG_LEVEL=${LOG_LEVEL:-debug}
+    volumes:
+      # Mount source code for live reload in development
+      - ./src:/app/src
+      - ./config:/app/config
+      - ./migrations:/app/migrations
+      - ./models:/app/models
+      - ./logs:/app/logs
+    ports:
+      - "${PORT:-3000}:3000"
+    depends_on:
+      db:
+        condition: service_healthy
+    networks:
+      - market-data-network
+    restart: unless-stopped
+    # Override entrypoint for development to use nodemon with live reload
+    entrypoint: /bin/sh
+    command: -c "/usr/local/bin/wait-for-db.sh && npx sequelize-cli db:migrate && npm install -g nodemon && nodemon src/server.js"
+
+  # Nginx Reverse Proxy
+  nginx:
+    image: nginx:alpine
+    container_name: market-data-nginx
+    ports:
+      - "80:80"
+    volumes:
+      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
+    depends_on:
+      - api
+    networks:
+      - market-data-network
+    restart: unless-stopped
+    healthcheck:
+      test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+
+volumes:
+  market_data_db_data:
+    driver: local
+
+networks:
+  market-data-network:
+    driver: bridge
+

+ 45 - 0
docker/entrypoint.sh

@@ -0,0 +1,45 @@
+#!/bin/sh
+set -e
+
+echo "Starting Market Data Service API container..."
+
+# Wait for database to be ready
+if [ -f /usr/local/bin/wait-for-db.sh ]; then
+    /usr/local/bin/wait-for-db.sh
+else
+    echo "Waiting for database using pg_isready..."
+    host="${DB_HOST:-db}"
+    port="${DB_PORT:-5432}"
+    user="${DB_USER:-postgres}"
+    max_attempts=30
+    attempt=0
+    
+    while [ $attempt -lt $max_attempts ]; do
+        if PGPASSWORD="${DB_PASSWORD}" pg_isready -h "$host" -p "$port" -U "$user" >/dev/null 2>&1; then
+            echo "Database is ready!"
+            break
+        fi
+        attempt=$((attempt + 1))
+        echo "Waiting for database... ($attempt/$max_attempts)"
+        sleep 2
+    done
+    
+    if [ $attempt -eq $max_attempts ]; then
+        echo "ERROR: Database failed to become ready"
+        exit 1
+    fi
+fi
+
+# Run database migrations
+echo "Running database migrations..."
+npx sequelize-cli db:migrate || {
+    echo "ERROR: Database migration failed"
+    exit 1
+}
+
+echo "Migrations completed successfully"
+
+# Start the application
+echo "Starting Node.js application..."
+exec "$@"
+

+ 27 - 0
docker/init-db.sh

@@ -0,0 +1,27 @@
+#!/bin/bash
+set -e
+
+# Database initialization script for PostgreSQL
+# This script creates the database if it doesn't exist
+# This runs automatically when PostgreSQL container starts for the first time
+
+DB_NAME="${POSTGRES_DB:-financial_data}"
+DB_USER="${POSTGRES_USER:-postgres}"
+
+echo "Initializing database ${DB_NAME}..."
+
+# The database is already created by POSTGRES_DB environment variable
+# We just need to ensure it exists and set up permissions
+psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
+    -- Grant all privileges to the postgres user
+    GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};
+    
+    -- Connect to the database and set up schema
+    \c ${DB_NAME}
+    
+    -- Create extensions if needed
+    CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+EOSQL
+
+echo "Database ${DB_NAME} initialized successfully."
+

+ 29 - 0
docker/wait-for-db.sh

@@ -0,0 +1,29 @@
+#!/bin/sh
+set -e
+
+# Wait for PostgreSQL to be ready
+# Usage: wait-for-db.sh [host] [port] [user] [database]
+
+host="${DB_HOST:-db}"
+port="${DB_PORT:-5432}"
+user="${DB_USER:-postgres}"
+database="${DB_NAME:-financial_data}"
+max_attempts=30
+attempt=0
+
+echo "Waiting for PostgreSQL to be ready at ${host}:${port}..."
+
+while [ $attempt -lt $max_attempts ]; do
+    if PGPASSWORD="${DB_PASSWORD}" pg_isready -h "$host" -p "$port" -U "$user" -d "$database" >/dev/null 2>&1; then
+        echo "PostgreSQL is ready!"
+        exit 0
+    fi
+    
+    attempt=$((attempt + 1))
+    echo "Attempt $attempt/$max_attempts: PostgreSQL is not ready yet. Waiting..."
+    sleep 2
+done
+
+echo "PostgreSQL failed to become ready after $max_attempts attempts"
+exit 1
+

+ 114 - 0
nginx/nginx.conf

@@ -0,0 +1,114 @@
+# Nginx configuration for development environment
+# HTTP only, WebSocket support enabled
+
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+    worker_connections 1024;
+}
+
+http {
+    include /etc/nginx/mime.types;
+    default_type application/octet-stream;
+
+    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+                    '$status $body_size_sent "$http_referer" '
+                    '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log /var/log/nginx/access.log main;
+
+    sendfile on;
+    tcp_nopush on;
+    tcp_nodelay on;
+    keepalive_timeout 65;
+    types_hash_max_size 2048;
+    client_max_body_size 50M;
+
+    # Gzip compression
+    gzip on;
+    gzip_vary on;
+    gzip_proxied any;
+    gzip_comp_level 6;
+    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
+
+    # Upstream API server
+    upstream api {
+        server api:3000;
+    }
+
+    server {
+        listen 80;
+        server_name localhost;
+
+        # Health check endpoint
+        location /health {
+            proxy_pass http://api/health;
+            proxy_http_version 1.1;
+            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;
+            
+            access_log off;
+        }
+
+        # WebSocket support for Socket.io
+        location /socket.io/ {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            
+            # WebSocket upgrade headers
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+            
+            # Standard proxy headers
+            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 timeouts (Socket.io uses long-lived connections)
+            proxy_read_timeout 86400s;
+            proxy_send_timeout 86400s;
+            proxy_connect_timeout 60s;
+            
+            # Disable buffering for real-time data
+            proxy_buffering off;
+            proxy_cache off;
+        }
+
+        # API endpoints
+        location /api/ {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            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;
+            
+            # Timeout settings
+            proxy_connect_timeout 60s;
+            proxy_send_timeout 60s;
+            proxy_read_timeout 60s;
+            
+            # Buffer settings
+            proxy_buffering on;
+            proxy_buffer_size 4k;
+            proxy_buffers 8 4k;
+        }
+
+        # Root endpoint
+        location / {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            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;
+        }
+    }
+}
+

+ 164 - 0
nginx/nginx.prod.conf

@@ -0,0 +1,164 @@
+# Nginx configuration for production environment
+# HTTP to HTTPS redirect, SSL/TLS, WebSocket support
+
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+    worker_connections 2048;
+    use epoll;
+}
+
+http {
+    include /etc/nginx/mime.types;
+    default_type application/octet-stream;
+
+    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+                    '$status $body_size_sent "$http_referer" '
+                    '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log /var/log/nginx/access.log main;
+
+    sendfile on;
+    tcp_nopush on;
+    tcp_nodelay on;
+    keepalive_timeout 65;
+    types_hash_max_size 2048;
+    client_max_body_size 50M;
+
+    # Hide nginx version
+    server_tokens off;
+
+    # Gzip compression
+    gzip on;
+    gzip_vary on;
+    gzip_proxied any;
+    gzip_comp_level 6;
+    gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss;
+
+    # Rate limiting (optional, adjust as needed)
+    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m;
+    limit_req_zone $binary_remote_addr zone=ws_limit:10m rate=10r/s;
+
+    # Upstream API server
+    upstream api {
+        server api:3000;
+        keepalive 32;
+    }
+
+    # HTTP server - redirect to HTTPS
+    server {
+        listen 80;
+        server_name _;
+
+        # Allow Let's Encrypt challenges
+        location /.well-known/acme-challenge/ {
+            root /var/www/certbot;
+        }
+
+        # Redirect all other traffic to HTTPS
+        location / {
+            return 301 https://$host$request_uri;
+        }
+    }
+
+    # HTTPS server
+    server {
+        listen 443 ssl http2;
+        server_name _;
+
+        # SSL Configuration
+        # Update these paths to match your SSL certificate locations
+        ssl_certificate /etc/nginx/ssl/certs/fullchain.pem;
+        ssl_certificate_key /etc/nginx/ssl/private/privkey.pem;
+
+        # SSL Security Settings
+        ssl_protocols TLSv1.2 TLSv1.3;
+        ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
+        ssl_prefer_server_ciphers off;
+        ssl_session_cache shared:SSL:10m;
+        ssl_session_timeout 10m;
+        ssl_session_tickets off;
+
+        # Security Headers
+        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
+        add_header X-Frame-Options "DENY" 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;
+
+        # Health check endpoint (no rate limiting)
+        location /health {
+            proxy_pass http://api/health;
+            proxy_http_version 1.1;
+            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;
+            
+            access_log off;
+        }
+
+        # WebSocket support for Socket.io (with rate limiting)
+        location /socket.io/ {
+            limit_req zone=ws_limit burst=20 nodelay;
+            
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            
+            # WebSocket upgrade headers
+            proxy_set_header Upgrade $http_upgrade;
+            proxy_set_header Connection "upgrade";
+            
+            # Standard proxy headers
+            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 timeouts (Socket.io uses long-lived connections)
+            proxy_read_timeout 86400s;
+            proxy_send_timeout 86400s;
+            proxy_connect_timeout 60s;
+            
+            # Disable buffering for real-time data
+            proxy_buffering off;
+            proxy_cache off;
+        }
+
+        # API endpoints (with rate limiting)
+        location /api/ {
+            limit_req zone=api_limit burst=50 nodelay;
+            
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            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;
+            
+            # Timeout settings
+            proxy_connect_timeout 60s;
+            proxy_send_timeout 60s;
+            proxy_read_timeout 60s;
+            
+            # Buffer settings
+            proxy_buffering on;
+            proxy_buffer_size 4k;
+            proxy_buffers 8 4k;
+        }
+
+        # Root endpoint
+        location / {
+            proxy_pass http://api;
+            proxy_http_version 1.1;
+            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;
+        }
+    }
+}
+