Browse Source

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 11 tháng trước cách đây
mục cha
commit
7c642d6730
10 tập tin đã thay đổi với 1202 bổ sung và 0 xóa
  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;
+        }
+    }
+}
+