ECL Calculator - Setup and Deployment Guide

Table of Contents

1. Introduction

This guide provides comprehensive instructions for setting up and deploying the ECL Calculator application in various environments. Whether you're looking to set up a local development environment or deploy to a production server, this document will walk you through the necessary steps.

The ECL Calculator is a full-stack application with:

Target Audience

This guide assumes familiarity with basic system administration, command-line operations, and web application architecture. Specific sections may require more specialized knowledge of database management, containerization, or cloud services.

2. Prerequisites

For Local Development

For Production Deployment

For Docker Deployment

For Kubernetes Deployment

3. Local Development Setup

Getting the Source Code

Clone the repository from your version control system:

git clone https://github.com/your-organization/ecl-calculator.git
cd ecl-calculator

Database Setup (Local)

The ECL Calculator requires a PostgreSQL database. Here's how to set it up locally:

1. Install PostgreSQL

On Ubuntu/Debian:

sudo apt update
sudo apt install postgresql postgresql-contrib

On macOS with Homebrew:

brew install postgresql
brew services start postgresql

On Windows:

Download and install PostgreSQL from the official website.

2. Create Database and User

sudo -u postgres psql

CREATE DATABASE ecl_calculator;
CREATE USER ecl_user WITH PASSWORD 'your_secure_password';
ALTER ROLE ecl_user SET client_encoding TO 'utf8';
ALTER ROLE ecl_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE ecl_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE ecl_calculator TO ecl_user;
\q
Important Security Note

Always use strong, unique passwords in production. The example password above is for demonstration purposes only.

Python Environment Setup

1. Create a Virtual Environment

python -m venv venv
source venv/bin/activate  # On Windows, use: venv\Scripts\activate

2. Install Dependencies

pip install -r requirements.txt

If requirements.txt is not available, install the necessary packages:

pip install flask flask-cors flask-login flask-sqlalchemy flask-wtf gunicorn
pip install psycopg2-binary pandas numpy email-validator werkzeug

React Frontend Setup

1. Navigate to the React Project Directory

cd react-ecl-calculator

2. Install Node.js Dependencies

npm install

3. Build the React App (for Production)

npm run build

For development, you can use:

npm start

Configuration

1. Environment Variables

Create a .env file in the project root with the following variables:

FLASK_APP=main.py
FLASK_ENV=development  # Use 'production' for production deployments
DATABASE_URL=postgresql://ecl_user:your_secure_password@localhost/ecl_calculator
SESSION_SECRET=your_session_secret_key
ADMIN_EMAIL=admin@example.com

2. React Frontend Configuration

Configure the API base URL in react-ecl-calculator/src/config/environments.js:

// For local development
const development = {
  apiBaseUrl: 'http://localhost:5000/api'
};

// For testing
const testing = {
  apiBaseUrl: 'http://test-server.example.com/api'
};

// For production
const production = {
  apiBaseUrl: 'https://production-server.example.com/api'
};

Running the Application Locally

1. Start the Flask Backend

From the project root directory:

python -m flask run

For production-like setup with Gunicorn:

gunicorn --bind 0.0.0.0:5000 --workers 4 main:app

2. Start the React Development Server (Optional)

In a separate terminal, navigate to the React directory:

cd react-ecl-calculator
npm start

Development Tip

When running both Flask and React development servers, your React app will be available at http://localhost:3000, while the Flask server will be at http://localhost:5000. The React development server will proxy API requests to the Flask backend.

3. Create an Admin User

To access the application, you'll need an admin user. You can create one using the provided script:

python create_demo_admin.py

This will create a user with the credentials specified in the script (usually admin@example.com / Admin123!).

4. Production Deployment

AWS EC2 Deployment

1. Launch an EC2 Instance

  1. Sign in to the AWS Management Console
  2. Navigate to EC2 service
  3. Click "Launch Instance"
  4. Choose Amazon Linux 2 or Ubuntu 20.04 LTS
  5. Select an instance type (t2.micro for small deployments, t2.medium or larger for production)
  6. Configure instance details, storage, and security groups
  7. Create or select an existing key pair for SSH access
  8. Launch the instance

2. Configure Security Groups

Ensure your security group allows the following inbound traffic:

  • SSH (port 22) from your IP address
  • HTTP (port 80) from anywhere
  • HTTPS (port 443) from anywhere

3. Connect to Your EC2 Instance

ssh -i /path/to/your-key.pem ec2-user@your-instance-public-dns

For Ubuntu instances, use:

ssh -i /path/to/your-key.pem ubuntu@your-instance-public-dns

4. Update System Packages

sudo apt update
sudo apt upgrade -y

PostgreSQL Database Setup

1. Install PostgreSQL

sudo apt install postgresql postgresql-contrib -y

2. Create Database and User

sudo -u postgres psql

CREATE DATABASE ecl_calculator;
CREATE USER ecl_user WITH PASSWORD 'your_production_password';
ALTER ROLE ecl_user SET client_encoding TO 'utf8';
ALTER ROLE ecl_user SET default_transaction_isolation TO 'read committed';
ALTER ROLE ecl_user SET timezone TO 'UTC';
GRANT ALL PRIVILEGES ON DATABASE ecl_calculator TO ecl_user;
\q

3. Configure PostgreSQL for Remote Access (Optional)

If your database will be on a separate server, you'll need to enable remote access:

Edit the PostgreSQL configuration file:

sudo nano /etc/postgresql/12/main/postgresql.conf

Find and uncomment the line:

#listen_addresses = 'localhost'

Change it to:

listen_addresses = '*'

Edit the client authentication configuration:

sudo nano /etc/postgresql/12/main/pg_hba.conf

Add the following line to allow access from your application server:

host    all             all             your_app_server_ip/32         md5

Restart PostgreSQL:

sudo systemctl restart postgresql
Security Warning

Exposing PostgreSQL to the internet is a significant security risk. Consider using VPC, security groups, or SSH tunneling to secure database connections instead of opening direct access.

Application Deployment

1. Install Required System Packages

sudo apt install python3-pip python3-venv nginx git -y

2. Create a Deployment User (Optional but Recommended)

sudo adduser ecl_app
sudo usermod -aG sudo ecl_app
su - ecl_app

3. Clone the Repository

git clone https://github.com/your-organization/ecl-calculator.git
cd ecl-calculator

4. Set Up Python Environment

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install gunicorn

5. Build the React Frontend

cd react-ecl-calculator
npm install
npm run build
cd ..

6. Configure Environment Variables

Create a .env file:

nano .env

Add the following content:

FLASK_APP=main.py
FLASK_ENV=production
DATABASE_URL=postgresql://ecl_user:your_production_password@localhost/ecl_calculator
SESSION_SECRET=your_production_secret_key
ADMIN_EMAIL=admin@your-company.com

Load environment variables in systemd service (see systemd section below)

Nginx Setup

1. Create Nginx Configuration

sudo nano /etc/nginx/sites-available/ecl-calculator

Add the following configuration:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    location /static {
        alias /home/ecl_app/ecl-calculator/static;
        expires 30d;
    }

    location /react {
        alias /home/ecl_app/ecl-calculator/react-ecl-calculator/build;
        try_files $uri $uri/ /react/index.html;
        expires 30d;
    }

    location / {
        proxy_pass http://localhost:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

2. Enable the Nginx Configuration

sudo ln -s /etc/nginx/sites-available/ecl-calculator /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

SSL Configuration

1. Install Certbot

sudo apt install certbot python3-certbot-nginx -y

2. Obtain SSL Certificate

sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Follow the prompts to configure HTTPS.

3. Auto-renewal Setup

Certbot sets up auto-renewal automatically. You can test it with:

sudo certbot renew --dry-run

Systemd Service Setup

1. Create a Systemd Service File

sudo nano /etc/systemd/system/ecl-calculator.service

Add the following content:

[Unit]
Description=ECL Calculator Application
After=network.target postgresql.service

[Service]
User=ecl_app
Group=www-data
WorkingDirectory=/home/ecl_app/ecl-calculator
Environment="PATH=/home/ecl_app/ecl-calculator/venv/bin"
EnvironmentFile=/home/ecl_app/ecl-calculator/.env
ExecStart=/home/ecl_app/ecl-calculator/venv/bin/gunicorn --workers 4 --bind 0.0.0.0:5000 main:app
Restart=always

[Install]
WantedBy=multi-user.target

2. Start and Enable the Service

sudo systemctl daemon-reload
sudo systemctl start ecl-calculator
sudo systemctl enable ecl-calculator
sudo systemctl status ecl-calculator

Checking Service Status

You can monitor the application logs with:

sudo journalctl -u ecl-calculator -f

5. Docker Deployment

Dockerfile Setup

Create a Dockerfile in the project root:

FROM python:3.9-slim

WORKDIR /app

# Install dependencies for building Python packages
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn

# Copy the application code
COPY . .

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV FLASK_APP=main.py
ENV FLASK_ENV=production

# Expose the application port
EXPOSE 5000

# Command to run the application
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "main:app"]

Docker Compose Setup

Create a docker-compose.yml file:

version: '3.8'

services:
  db:
    image: postgres:13
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_PASSWORD=your_secure_password
      - POSTGRES_USER=ecl_user
      - POSTGRES_DB=ecl_calculator
    restart: always
    
  web:
    build: .
    restart: always
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://ecl_user:your_secure_password@db/ecl_calculator
      - SESSION_SECRET=your_docker_secret_key
      - ADMIN_EMAIL=admin@example.com
    ports:
      - "5000:5000"
      
  nginx:
    image: nginx:1.21
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./nginx/ssl:/etc/nginx/ssl
      - ./static:/app/static
      - ./react-ecl-calculator/build:/app/react
    depends_on:
      - web
    restart: always

volumes:
  postgres_data:

Create the Nginx configuration:

mkdir -p nginx/conf
nano nginx/conf/default.conf

Add the following configuration:

server {
    listen 80;
    server_name localhost;

    location /static {
        alias /app/static;
        expires 30d;
    }

    location /react {
        alias /app/react;
        try_files $uri $uri/ /react/index.html;
        expires 30d;
    }

    location / {
        proxy_pass http://web:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Building and Running Docker Containers

1. Build the React App

cd react-ecl-calculator
npm install
npm run build
cd ..

2. Start the Docker Services

docker-compose up -d

3. Create an Admin User

docker-compose exec web python create_demo_admin.py

4. Stopping the Services

docker-compose down

Docker Tips

For scaling in production, you may want to separate the database into its own managed service (like AWS RDS or Azure Database for PostgreSQL) rather than running it in a container.

6. Kubernetes Deployment

Kubernetes Manifests

Create a directory for Kubernetes manifests:

mkdir -p kubernetes

1. Namespace Configuration

cat > kubernetes/namespace.yaml << EOF
apiVersion: v1
kind: Namespace
metadata:
  name: ecl-calculator
EOF

2. ConfigMap for Environment Variables

cat > kubernetes/configmap.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: ecl-calculator-config
  namespace: ecl-calculator
data:
  FLASK_APP: "main.py"
  FLASK_ENV: "production"
  ADMIN_EMAIL: "admin@example.com"
EOF

3. Secret for Sensitive Data

cat > kubernetes/secret.yaml << EOF
apiVersion: v1
kind: Secret
metadata:
  name: ecl-calculator-secrets
  namespace: ecl-calculator
type: Opaque
data:
  DATABASE_URL: BASE64_ENCODED_DB_URL
  SESSION_SECRET: BASE64_ENCODED_SECRET
EOF

Replace BASE64_ENCODED_* with the actual base64-encoded values:

echo -n "postgresql://ecl_user:your_password@postgres-service/ecl_calculator" | base64
echo -n "your_kubernetes_secret_key" | base64

4. Persistent Volume for PostgreSQL

cat > kubernetes/postgres-pv.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
  namespace: ecl-calculator
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
EOF

5. PostgreSQL Deployment

cat > kubernetes/postgres-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: ecl-calculator
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:13
        ports:
        - containerPort: 5432
        env:
        - name: POSTGRES_DB
          value: ecl_calculator
        - name: POSTGRES_USER
          value: ecl_user
        - name: POSTGRES_PASSWORD
          valueFrom:
            secretKeyRef:
              name: ecl-calculator-secrets
              key: POSTGRES_PASSWORD
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: postgres-storage
        persistentVolumeClaim:
          claimName: postgres-pvc
EOF

6. PostgreSQL Service

cat > kubernetes/postgres-service.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
  namespace: ecl-calculator
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432
EOF

7. Web Application Deployment

cat > kubernetes/web-deployment.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ecl-calculator
  namespace: ecl-calculator
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ecl-calculator
  template:
    metadata:
      labels:
        app: ecl-calculator
    spec:
      containers:
      - name: ecl-calculator
        image: your-docker-registry/ecl-calculator:latest
        ports:
        - containerPort: 5000
        envFrom:
        - configMapRef:
            name: ecl-calculator-config
        - secretRef:
            name: ecl-calculator-secrets
        readinessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 5
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 5000
          initialDelaySeconds: 15
          periodSeconds: 20
EOF

8. Web Application Service

cat > kubernetes/web-service.yaml << EOF
apiVersion: v1
kind: Service
metadata:
  name: ecl-calculator-service
  namespace: ecl-calculator
spec:
  selector:
    app: ecl-calculator
  ports:
  - port: 80
    targetPort: 5000
  type: ClusterIP
EOF

9. Ingress Configuration

cat > kubernetes/ingress.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ecl-calculator-ingress
  namespace: ecl-calculator
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - ecl-calculator.example.com
    secretName: ecl-calculator-tls
  rules:
  - host: ecl-calculator.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: ecl-calculator-service
            port:
              number: 80
EOF

Deploying to Kubernetes

1. Push Docker Image to Registry

# Build the image
docker build -t your-docker-registry/ecl-calculator:latest .

# Push to registry
docker push your-docker-registry/ecl-calculator:latest

2. Apply Kubernetes Manifests

kubectl apply -f kubernetes/namespace.yaml
kubectl apply -f kubernetes/configmap.yaml
kubectl apply -f kubernetes/secret.yaml
kubectl apply -f kubernetes/postgres-pv.yaml
kubectl apply -f kubernetes/postgres-deployment.yaml
kubectl apply -f kubernetes/postgres-service.yaml
kubectl apply -f kubernetes/web-deployment.yaml
kubectl apply -f kubernetes/web-service.yaml
kubectl apply -f kubernetes/ingress.yaml

3. Verify Deployment

kubectl get pods -n ecl-calculator
kubectl get services -n ecl-calculator
kubectl get ingress -n ecl-calculator

4. Initialize the Admin User

kubectl exec -it -n ecl-calculator \
  $(kubectl get pods -n ecl-calculator -l app=ecl-calculator -o jsonpath="{.items[0].metadata.name}") \
  -- python create_demo_admin.py

7. CI/CD Setup

GitHub Actions

Create a GitHub Actions workflow file:

mkdir -p .github/workflows
nano .github/workflows/ci-cd.yml

Add the following content:

name: ECL Calculator CI/CD

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:13
        env:
          POSTGRES_USER: ecl_user
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: ecl_calculator_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
        pip install pytest pytest-cov
    
    - name: Test with pytest
      env:
        DATABASE_URL: postgresql://ecl_user:postgres@localhost/ecl_calculator_test
        SESSION_SECRET: github_actions_secret
      run: |
        pytest --cov=./ --cov-report=xml
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v1
      
  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '14'
    
    - name: Build React app
      run: |
        cd react-ecl-calculator
        npm install
        npm run build
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v1
    
    - name: Login to Docker Hub
      uses: docker/login-action@v1
      with:
        username: ${{ secrets.DOCKER_HUB_USERNAME }}
        password: ${{ secrets.DOCKER_HUB_TOKEN }}
    
    - name: Build and push
      uses: docker/build-push-action@v2
      with:
        context: .
        push: true
        tags: your-docker-registry/ecl-calculator:latest
        
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Install kubectl
      uses: azure/setup-kubectl@v1
    
    - name: Set Kubernetes context
      uses: azure/k8s-set-context@v1
      with:
        kubeconfig: ${{ secrets.KUBE_CONFIG }}
    
    - name: Deploy to Kubernetes
      run: |
        kubectl apply -f kubernetes/web-deployment.yaml
        kubectl rollout restart deployment/ecl-calculator -n ecl-calculator

Jenkins Pipeline

Create a Jenkinsfile in the project root:

pipeline {
    agent {
        docker {
            image 'python:3.9'
        }
    }
    
    environment {
        DATABASE_URL = credentials('ecl-calculator-db-url')
        SESSION_SECRET = credentials('ecl-calculator-session-secret')
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'pip install -r requirements.txt'
                sh 'cd react-ecl-calculator && npm install && npm run build'
            }
        }
        
        stage('Test') {
            steps {
                sh 'pip install pytest pytest-cov'
                sh 'python -m pytest --cov=./ --cov-report=xml'
            }
        }
        
        stage('Build and Push Docker Image') {
            when {
                branch 'main'
            }
            steps {
                script {
                    docker.withRegistry('https://registry.example.com', 'docker-credentials') {
                        def customImage = docker.build("your-registry/ecl-calculator:${env.BUILD_ID}")
                        customImage.push()
                        customImage.push('latest')
                    }
                }
            }
        }
        
        stage('Deploy to Production') {
            when {
                branch 'main'
            }
            steps {
                withKubeConfig([credentialsId: 'kubeconfig']) {
                    sh 'kubectl apply -f kubernetes/web-deployment.yaml'
                    sh 'kubectl rollout restart deployment/ecl-calculator -n ecl-calculator'
                }
            }
        }
    }
    
    post {
        always {
            junit 'test-results/*.xml'
            publishHTML(target: [
                allowMissing: false,
                alwaysLinkToLastBuild: false,
                keepAll: true,
                reportDir: 'coverage',
                reportFiles: 'index.html',
                reportName: 'Coverage Report'
            ])
        }
    }
}

AWS CodePipeline

If using AWS CodePipeline, create a buildspec.yml file:

version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.9
      nodejs: 14
    commands:
      - npm install -g npm@latest
      
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
      - pip install -r requirements.txt
      - cd react-ecl-calculator && npm install && npm run build && cd ..
      - pip install pytest pytest-cov
      - python -m pytest
      
  build:
    commands:
      - echo Building the Docker image...
      - docker build -t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:latest .
      - docker tag $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:$CODEBUILD_RESOLVED_SOURCE_VERSION
      
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:latest
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:$CODEBUILD_RESOLVED_SOURCE_VERSION
      - echo Writing image definitions file...
      - echo "{\"ImageURI\":\"$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/ecl-calculator:$CODEBUILD_RESOLVED_SOURCE_VERSION\"}" > imageDefinition.json
      
artifacts:
  files:
    - imageDefinition.json
    - appspec.yml
    - taskdef.json

8. Monitoring and Maintenance

Logging Setup

1. Application Logging

Set up application logging in your main.py or app.py file:

import logging
import os
from logging.handlers import RotatingFileHandler

def setup_logging(app):
    log_level = os.environ.get('LOG_LEVEL', 'INFO')
    log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    log_dir = 'logs'
    
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)
    
    # File handler for all logs
    file_handler = RotatingFileHandler(
        os.path.join(log_dir, 'ecl-calculator.log'),
        maxBytes=10485760,  # 10MB
        backupCount=10
    )
    file_handler.setFormatter(logging.Formatter(log_format))
    
    # Error log handler
    error_handler = RotatingFileHandler(
        os.path.join(log_dir, 'error.log'),
        maxBytes=10485760,  # 10MB
        backupCount=10
    )
    error_handler.setLevel(logging.ERROR)
    error_handler.setFormatter(logging.Formatter(log_format))
    
    # Set up root logger
    root_logger = logging.getLogger()
    root_logger.setLevel(getattr(logging, log_level))
    root_logger.addHandler(file_handler)
    root_logger.addHandler(error_handler)
    
    # Set up app logger if Flask app is provided
    if app:
        app.logger.setLevel(getattr(logging, log_level))
        app.logger.addHandler(file_handler)
        app.logger.addHandler(error_handler)
        
        app.logger.info('Application logging initialized')

2. Nginx Logging

Enable detailed access and error logs in Nginx:

server {
    # ... other configuration ...
    
    access_log /var/log/nginx/ecl-calculator-access.log;
    error_log /var/log/nginx/ecl-calculator-error.log;
    
    # ... rest of configuration ...
}

3. Log Rotation

Set up log rotation for Nginx logs:

sudo nano /etc/logrotate.d/ecl-calculator

Add the following:

/var/log/nginx/ecl-calculator-*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        /usr/bin/systemctl reload nginx
    endscript
}

Monitoring Tools

1. Prometheus Setup (Basic)

Install Prometheus client for Python:

pip install prometheus-client

Add Prometheus metrics to your application:

from prometheus_client import Counter, Histogram, start_http_server
import time

# Create metrics
REQUEST_COUNT = Counter(
    'request_count', 'App Request Count',
    ['app_name', 'method', 'endpoint', 'http_status']
)
REQUEST_LATENCY = Histogram(
    'request_latency_seconds', 'Request latency',
    ['app_name', 'method', 'endpoint']
)

# Set up a Flask middleware to collect metrics
@app.before_request
def start_timer():
    g.start = time.time()

@app.after_request
def record_request(response):
    request_latency = time.time() - g.start
    REQUEST_LATENCY.labels(
        'ecl_calculator', 
        request.method, 
        request.path
    ).observe(request_latency)
    
    REQUEST_COUNT.labels(
        'ecl_calculator', 
        request.method, 
        request.path,
        response.status_code
    ).inc()
    
    return response

# Start Prometheus HTTP server on port 8000
start_http_server(8000)

2. Grafana Dashboard

Set up a basic Grafana dashboard to visualize Prometheus metrics.

3. Health Check Endpoint

Add a health check endpoint to your Flask application:

@app.route('/health')
def health_check():
    try:
        # Check database connection
        db.session.execute('SELECT 1')
        return jsonify(status='ok'), 200
    except Exception as e:
        app.logger.error(f"Health check failed: {str(e)}")
        return jsonify(status='error', message=str(e)), 500

Backup and Restore

1. Database Backup Script

Create a script for automated PostgreSQL backups:

#!/bin/bash
# backup.sh

# Configuration
BACKUP_DIR="/path/to/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
PGUSER="ecl_user"
PGPASSWORD="your_production_password"
DATABASE="ecl_calculator"
RETENTION_DAYS=14

# Create backup directory if it doesn't exist
mkdir -p $BACKUP_DIR

# Create the backup
pg_dump -U $PGUSER $DATABASE | gzip > $BACKUP_DIR/ecl_calculator_$TIMESTAMP.sql.gz

# Delete old backups
find $BACKUP_DIR -name "ecl_calculator_*.sql.gz" -type f -mtime +$RETENTION_DAYS -delete

Set up a cron job to run the backup script:

sudo crontab -e

Add this line to run the backup daily at 2 AM:

0 2 * * * /path/to/backup.sh

2. Database Restore Procedure

#!/bin/bash
# restore.sh

# Configuration
BACKUP_FILE=$1
PGUSER="ecl_user"
PGPASSWORD="your_production_password"
DATABASE="ecl_calculator"

# Check if backup file is provided
if [ -z "$BACKUP_FILE" ]; then
    echo "Usage: $0 "
    exit 1
fi

# Check if backup file exists
if [ ! -f "$BACKUP_FILE" ]; then
    echo "Backup file not found: $BACKUP_FILE"
    exit 1
fi

# Create a temporary database
psql -U $PGUSER -c "DROP DATABASE IF EXISTS ${DATABASE}_restore"
psql -U $PGUSER -c "CREATE DATABASE ${DATABASE}_restore"

# Restore to the temporary database
if [[ "$BACKUP_FILE" == *.gz ]]; then
    gunzip -c "$BACKUP_FILE" | psql -U $PGUSER -d ${DATABASE}_restore
else
    psql -U $PGUSER -d ${DATABASE}_restore -f "$BACKUP_FILE"
fi

# If successful, swap the databases
if [ $? -eq 0 ]; then
    echo "Restore to temporary database successful. Swapping databases..."
    
    # Disconnect all clients
    psql -U $PGUSER -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$DATABASE'"
    psql -U $PGUSER -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '${DATABASE}_restore'"
    
    # Rename databases
    psql -U $PGUSER -c "ALTER DATABASE $DATABASE RENAME TO ${DATABASE}_old"
    psql -U $PGUSER -c "ALTER DATABASE ${DATABASE}_restore RENAME TO $DATABASE"
    
    # Drop old database
    psql -U $PGUSER -c "DROP DATABASE ${DATABASE}_old"
    
    echo "Restore completed successfully"
else
    echo "Restore failed!"
    psql -U $PGUSER -c "DROP DATABASE ${DATABASE}_restore"
    exit 1
fi

3. Full Application Backup

Back up the entire application directory:

tar -czvf /path/to/backups/ecl-calculator-app-$(date +"%Y%m%d").tar.gz /path/to/ecl-calculator

9. Troubleshooting

Common Issues and Solutions

Database Connection Issues

Symptoms: Application fails to start with database connection errors

Solutions:

  • Verify that the DATABASE_URL environment variable is correctly set
  • Check that PostgreSQL is running: sudo systemctl status postgresql
  • Ensure the database user has the correct permissions: sudo -u postgres psql -c '\du'
  • Verify network connectivity: nc -zv <db_host> <db_port>
Application Fails to Start

Symptoms: Gunicorn fails to start the application

Solutions:

  • Check application logs: sudo journalctl -u ecl-calculator -n 100
  • Verify all required Python packages are installed: pip list
  • Test the application manually: flask run
  • Check for syntax errors: python -m py_compile main.py
Nginx Configuration Issues

Symptoms: "502 Bad Gateway" or "504 Gateway Timeout" errors

Solutions:

  • Check Nginx error logs: sudo tail -f /var/log/nginx/error.log
  • Verify Nginx configuration: sudo nginx -t
  • Ensure Gunicorn is running: ps aux | grep gunicorn
  • Check Nginx and application connectivity: curl -v http://localhost:5000/health
React Frontend Issues

Symptoms: Frontend not loading or displaying errors

Solutions:

  • Check browser console for JavaScript errors
  • Verify that React build files are in the correct location
  • Check API connectivity from the browser: curl -v http://your-domain.com/api/auth/user
  • Rebuild the React app: npm run build
Performance Issues

Symptoms: Slow application response or timeouts

Solutions:

  • Check server resources: top, free -m, df -h
  • Monitor Gunicorn worker usage: ps aux | grep gunicorn | wc -l
  • Adjust Gunicorn worker count: --workers=2*CPU_CORES+1
  • Optimize database queries using Flask-SQLAlchemy's engine_options
  • Add database indexes for frequently queried columns

Diagnostic Commands

Command Purpose
sudo systemctl status ecl-calculator Check application service status
sudo journalctl -u ecl-calculator -f Real-time application logs
sudo tail -f /var/log/nginx/error.log Nginx error logs
sudo -u postgres psql -c 'SELECT now();' Verify PostgreSQL is running
docker-compose logs -f Check Docker container logs
kubectl logs -f deployment/ecl-calculator -n ecl-calculator Check Kubernetes pod logs

10. Security Best Practices

Application Security

Server Security

Database Security

Transport Security

Security Reminder

Security is an ongoing process, not a one-time task. Regularly review your security measures, monitor for new vulnerabilities, and update your application and infrastructure accordingly.