# Production Migration Checklist
## Dev (SQLite) → Production (PostgreSQL)

⚠️ **CRITICAL**: Thực hiện toàn bộ checklist này trước khi push code lên production!

---

## 📋 Pre-Migration (Chuẩn Bị)

### 1️⃣ Backup Production Database
```bash
# Trên production server
pg_dump -U postgres bmc_db > /backups/bmc_db_$(date +%Y%m%d_%H%M%S).sql

# Hoặc nếu có managed hosting
# Sử dụng admin panel để backup
```

### 2️⃣ Backup Media & Static Files
```bash
# Trên production
tar -czf /backups/media_backup_$(date +%Y%m%d).tar.gz /path/to/media/
tar -czf /backups/static_backup_$(date +%Y%m%d).tar.gz /path/to/staticfiles/
```

### 3️⃣ Test Migration Locally
```bash
# Trên máy dev
python manage.py migrate --dry-run  # Nếu Django hỗ trợ
# Hoặc chạy migrations bình thường trên staging database
```

---

## 🔧 Development → Production Configuration

### 4️⃣ Update `BMC/settings.py`

#### A) Database Configuration (PostgreSQL)
```python
# ❌ BEFORE (SQLite)
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# ✅ AFTER (PostgreSQL)
import os
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv('DB_NAME', 'bmc_db'),
        'USER': os.getenv('DB_USER', 'postgres'),
        'PASSWORD': os.getenv('DB_PASSWORD'),
        'HOST': os.getenv('DB_HOST', 'localhost'),
        'PORT': os.getenv('DB_PORT', '5432'),
        'ATOMIC_REQUESTS': True,
        'CONN_MAX_AGE': 600,
        'OPTIONS': {
            'connect_timeout': 10,
            'options': '-c default_transaction_isolation=read_committed'
        }
    }
}
```

#### B) Security Settings
```python
# ✅ Production Mode
DEBUG = os.getenv('DEBUG', 'False') == 'True'  # ← MUST BE False!

SECRET_KEY = os.getenv('SECRET_KEY')  # ← Don't hardcode!

ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
# Example: 'bmc.com.vn,www.bmc.com.vn,api.bmc.com.vn'

CSRF_TRUSTED_ORIGINS = os.getenv('CSRF_TRUSTED_ORIGINS', '').split(',')

SECURE_SSL_REDIRECT = os.getenv('SECURE_SSL_REDIRECT', 'True') == 'True'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_SECURITY_POLICY = True
```

#### C) Static Files & Media
```python
# ✅ Production paths
STATIC_URL = '/static/'
STATIC_ROOT = '/var/www/bmc/staticfiles/'  # ← Absolute path!

MEDIA_URL = '/media/'
MEDIA_ROOT = '/var/www/bmc/media/'  # ← Absolute path!

# Cache busting
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
```

#### D) Logging Configuration
```python
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'file': {
            'level': 'WARNING',
            'class': 'logging.FileHandler',
            'filename': '/var/log/django/bmc.log',
            'formatter': 'verbose',
        },
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        }
    },
    'loggers': {
        'django': {
            'handlers': ['file', 'console'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}
```

#### E) Caching (Optional but Recommended)
```python
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.redis.RedisCache',
        'LOCATION': os.getenv('REDIS_URL', 'redis://127.0.0.1:6379/1'),
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}
```

---

## 🔐 Environment Variables (.env on Production)

```env
# Django Settings
DEBUG=False
SECRET_KEY=your-very-long-random-secret-key-here-min-50-chars

# Database (PostgreSQL)
DB_ENGINE=django.db.backends.postgresql
DB_NAME=bmc_db
DB_USER=bmc_user
DB_PASSWORD=secure_password_here_min_20_chars
DB_HOST=localhost
DB_PORT=5432

# Allowed Hosts
ALLOWED_HOSTS=bmc.com.vn,www.bmc.com.vn,api.bmc.com.vn
CSRF_TRUSTED_ORIGINS=https://bmc.com.vn,https://www.bmc.com.vn

# Security
SECURE_SSL_REDIRECT=True
SESSION_COOKIE_SECURE=True
CSRF_COOKIE_SECURE=True

# Email (if using Django mail)
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USE_TLS=True
EMAIL_HOST_USER=your-email@gmail.com
EMAIL_HOST_PASSWORD=app-password

# ChatGPT API
OPENAI_API_KEY=sk-your-production-key-here

# File Paths
STATIC_ROOT=/var/www/bmc/staticfiles/
MEDIA_ROOT=/var/www/bmc/media/

# Redis (Optional)
REDIS_URL=redis://localhost:6379/1

# Backup
BACKUP_PATH=/backups/django/
```

---

## 📦 Dependencies

### 5️⃣ Update `requirements.txt`

```bash
# Add PostgreSQL driver
pip install psycopg2-binary==2.9.9
# OR
pip install psycopg2==2.9.9  # (requires gcc)

# Update requirements.txt
pip freeze > requirements.txt
```

**Key packages needed:**
```
Django==4.2.x
psycopg2-binary==2.9.9
python-decouple==3.8
gunicorn==21.x
Pillow==10.x  # For image handling
redis==5.x  # (if using Redis)
django-redis==5.x
celery==5.x  # (if using async tasks)
```

### 6️⃣ Verify on Production Server

```bash
# SSH to production server
ssh user@your-production-server.com

# Go to project directory
cd /var/www/bmc

# Activate virtualenv
source venv/bin/activate

# Upgrade pip
pip install --upgrade pip

# Install dependencies
pip install -r requirements.txt

# Verify PostgreSQL connection
python manage.py dbshell
```

---

## 🔄 Database Migration Steps

### 7️⃣ Run Migrations on Production

⚠️ **IMPORTANT**: Do this AFTER database is configured!

```bash
# SSH to production server
ssh user@your-production-server.com
cd /var/www/bmc
source venv/bin/activate

# Check migration status (don't apply yet!)
python manage.py showmigrations

# Run migrations
python manage.py migrate

# Create superuser if needed
python manage.py createsuperuser

# Verify migrations
python manage.py showmigrations
```

---

## 🎨 Static & Media Files

### 8️⃣ Collect Static Files

```bash
# On production server
python manage.py collectstatic --noinput --clear

# Verify permissions
sudo chown -R www-data:www-data /var/www/bmc/staticfiles/
sudo chown -R www-data:www-data /var/www/bmc/media/
sudo chmod -R 755 /var/www/bmc/staticfiles/
sudo chmod -R 755 /var/www/bmc/media/
```

### 9️⃣ Restore Media Files (if needed)

```bash
# If you had user uploads in development
# Copy from dev to production
tar -czf media_backup.tar.gz /path/to/dev/media/

# Transfer to production
scp media_backup.tar.gz user@production:/tmp/

# Extract on production
cd /var/www/bmc
tar -xzf /tmp/media_backup.tar.gz -C media/
sudo chown -R www-data:www-data media/
```

---

## 🚀 Web Server Configuration

### 🔟 Gunicorn Setup (if using)

```bash
# Create gunicorn socket service
sudo vim /etc/systemd/system/bmc-gunicorn.socket
```

```ini
[Unit]
Description=BMC Gunicorn Socket
After=network.target

[Socket]
ListenStream=/var/run/gunicorn.sock
Accept=false

[Install]
WantedBy=sockets.target
```

```bash
sudo vim /etc/systemd/system/bmc-gunicorn.service
```

```ini
[Unit]
Description=BMC Gunicorn Application Server
Requires=bmc-gunicorn.socket
After=network.target

[Service]
Type=notify
User=www-data
Group=www-data
WorkingDirectory=/var/www/bmc
ExecStart=/var/www/bmc/venv/bin/gunicorn \
          --workers 4 \
          --worker-class sync \
          --bind unix:/var/run/gunicorn.sock \
          --timeout 120 \
          BMC.wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
KillSignal=SIGTERM
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
```

```bash
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable bmc-gunicorn.socket
sudo systemctl start bmc-gunicorn.socket
sudo systemctl enable bmc-gunicorn.service
sudo systemctl start bmc-gunicorn.service
```

### 1️⃣1️⃣ Nginx Configuration

```bash
sudo vim /etc/nginx/sites-available/bmc
```

```nginx
upstream bmc_app {
    server unix:/var/run/gunicorn.sock fail_timeout=0;
}

server {
    listen 80;
    server_name bmc.com.vn www.bmc.com.vn;
    return 301 https://$server_name$request_uri;  # Redirect to HTTPS
}

server {
    listen 443 ssl http2;
    server_name bmc.com.vn www.bmc.com.vn;
    
    # SSL Certificates (Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/bmc.com.vn/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bmc.com.vn/privkey.pem;
    
    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    
    # Logging
    access_log /var/log/nginx/bmc_access.log;
    error_log /var/log/nginx/bmc_error.log;
    
    # Static files
    location /static/ {
        alias /var/www/bmc/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
    
    # Media files
    location /media/ {
        alias /var/www/bmc/media/;
        expires 7d;
    }
    
    # Proxy to Gunicorn
    location / {
        proxy_pass http://bmc_app;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_read_timeout 120s;
    }
    
    # Health check
    location /health/ {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}
```

```bash
# Enable site
sudo ln -s /etc/nginx/sites-available/bmc /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```

---

## ✅ Pre-Launch Testing

### 1️⃣2️⃣ Testing Checklist

```bash
# On production, test all critical features:

# 1. Check admin panel
curl -I https://bmc.com.vn/admin/

# 2. Check homepage
curl -I https://bmc.com.vn/

# 3. Check product pages
curl -I https://bmc.com.vn/products/

# 4. Check static files load
curl -I https://bmc.com.vn/static/css/style.css

# 5. Check media files
curl -I https://bmc.com.vn/media/sample.jpg

# 6. Check chatbot API
curl -X POST https://bmc.com.vn/api/chatbot/ \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello"}'

# 7. Check logs for errors
tail -f /var/log/django/bmc.log
tail -f /var/log/nginx/bmc_error.log

# 8. Check database connection
python manage.py dbshell
\dt  # List tables

# 9. Health check
curl https://bmc.com.vn/health/
```

---

## 🔄 Git Before Merge

### 1️⃣3️⃣ Clean Git History

```bash
# On dev machine, before pushing

# 1. Ensure all changes are committed
git status
git add .
git commit -m "chore: prepare for production deployment"

# 2. Update code from main (if team is working)
git pull origin main

# 3. Check branch status
git log --oneline -5

# 4. Create production branch (optional but recommended)
git checkout -b production
git push origin production

# 5. Or merge to main
git checkout main
git merge development
git push origin main
```

---

## 🚨 Common Issues & Solutions

### Issue: "Database does not exist"
```bash
# Solution: Create database
createdb -U postgres bmc_db

# Or from psql:
sudo -u postgres psql
CREATE DATABASE bmc_db;
CREATE USER bmc_user WITH PASSWORD 'password';
ALTER ROLE bmc_user SET client_encoding TO 'utf8';
ALTER ROLE bmc_user SET default_transaction_isolation TO 'read_committed';
ALTER ROLE bmc_user SET default_transaction_deferrable TO on;
GRANT ALL PRIVILEGES ON DATABASE bmc_db TO bmc_user;
\q
```

### Issue: "Permission Denied" on media/static folders
```bash
# Solution: Fix permissions
sudo chown -R www-data:www-data /var/www/bmc/media
sudo chown -R www-data:www-data /var/www/bmc/staticfiles
sudo chmod -R 755 /var/www/bmc/media
sudo chmod -R 755 /var/www/bmc/staticfiles
```

### Issue: "CSRF token missing" or "Forbidden"
```python
# Check CSRF settings in settings.py
CSRF_TRUSTED_ORIGINS = [
    'https://bmc.com.vn',
    'https://www.bmc.com.vn'
]

# Also check nginx headers are forwarded
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
```

### Issue: "static/css/style.css not found"
```bash
# Solution: Collectstatic
python manage.py collectstatic --noinput --clear

# Check file exists
ls -la /var/www/bmc/staticfiles/css/style.css
```

### Issue: "Chat API returns 401 Unauthorized"
```bash
# Check OPENAI_API_KEY in .env
echo $OPENAI_API_KEY

# Restart gunicorn
sudo systemctl restart bmc-gunicorn
```

---

## 📋 Final Deployment Checklist

- [ ] Backup production database & files
- [ ] Test migrations locally
- [ ] Update settings.py for PostgreSQL
- [ ] Set all environment variables in production .env
- [ ] Install psycopg2 on production
- [ ] Pull latest code from git
- [ ] Run migrations: `python manage.py migrate`
- [ ] Collectstatic: `python manage.py collectstatic --noinput`
- [ ] Create superuser if needed
- [ ] Test admin panel works
- [ ] Test homepage loads
- [ ] Test chatbot API responds
- [ ] Check logs for errors
- [ ] Monitor error rate first 24 hours
- [ ] Set up automated backups
- [ ] Document production server details
- [ ] Train team on deployment process

---

## 🔗 Related Documentation

- [Deployment Guide](DEPLOYMENT_GUIDE.md)
- [Backup Guide](../backups/README.md)
- [Environment Setup](../scripts/README.md)

---

**⏰ Typical migration time**: 30-60 minutes  
**🆘 Support**: Check logs first, then contact DevOps team  
**📝 Last Updated**: April 21, 2026
