# Database Migration Plan: SQLite → PostgreSQL

## Overview
This document outlines the migration strategy for moving from SQLite (development) to PostgreSQL (production) for both the Backend API and CMS.

## Current State
- **Backend**: Uses SQLite with TypeORM entities
- **CMS**: Uses SQLite with Strapi's internal database
- **Development**: Both use local SQLite files
- **Production**: Need PostgreSQL for scalability and reliability

## Migration Steps

### Phase 1: Database Schema Preparation

#### 1.1 Update Backend Database Configuration
```typescript
// backend/src/config/database.config.ts
export default () => ({
  database: {
    type: process.env.DATABASE_TYPE || 'sqlite',
    host: process.env.DATABASE_HOST || 'localhost',
    port: parseInt(process.env.DATABASE_PORT, 10) || 5432,
    username: process.env.DATABASE_USERNAME || 'placebo_user',
    password: process.env.DATABASE_PASSWORD || 'placebo_password',
    database: process.env.DATABASE_NAME || 'placebo_backend_db',
    synchronize: process.env.NODE_ENV !== 'production',
    logging: process.env.NODE_ENV !== 'production',
    entities: [__dirname + '/../**/*.entity{.ts,.js}'],
    migrations: [__dirname + '/../migrations/*{.ts,.js}'],
    cli: {
      migrationsDir: 'src/migrations',
    },
  },
});
```

#### 1.2 Create TypeORM Migrations
```bash
# Generate migration for existing schema
cd backend
npm run typeorm:generate-migration --name=InitialSchema

# Create migration files for PostgreSQL compatibility
npm run typeorm:create-migration --name=AddPostgresSupport
```

#### 1.3 Update CMS Database Configuration
```javascript
// cms/cms/config/database.js
module.exports = ({ env }) => ({
  connection: {
    client: env('DATABASE_CLIENT', 'sqlite'),
    connection: {
      host: env('DATABASE_HOST', 'localhost'),
      port: env.int('DATABASE_PORT', 5432),
      database: env('DATABASE_NAME', 'placebo_cms_db'),
      user: env('DATABASE_USERNAME', 'placebo_user'),
      password: env('DATABASE_PASSWORD', 'placebo_password'),
      ssl: env.bool('DATABASE_SSL', false),
    },
    debug: false,
  },
});
```

### Phase 2: Data Migration

#### 2.1 Export SQLite Data
```bash
# Export Backend SQLite data
sqlite3 backend/data.db .dump > backend-data.sql

# Export CMS SQLite data
sqlite3 cms/cms/.tmp/data.db .dump > cms-data.sql
```

#### 2.2 Transform SQL for PostgreSQL
Create transformation scripts:
```python
# scripts/transform-sqlite-to-postgres.py
import re

def transform_sqlite_to_postgres(sqlite_sql):
    # Remove SQLite-specific syntax
    sqlite_sql = re.sub(r'AUTOINCREMENT', 'SERIAL', sqlite_sql)
    sqlite_sql = re.sub(r'INTEGER PRIMARY KEY', 'SERIAL PRIMARY KEY', sqlite_sql)
    sqlite_sql = re.sub(r'BLOB', 'BYTEA', sqlite_sql)
    sqlite_sql = re.sub(r'DATETIME', 'TIMESTAMP', sqlite_sql)
    return sqlite_sql
```

#### 2.3 Import to PostgreSQL
```bash
# Create databases
psql -U placebo_user -h localhost -d placebo_db -c "CREATE DATABASE placebo_backend_db;"
psql -U placebo_user -h localhost -d placebo_db -c "CREATE DATABASE placebo_cms_db;"

# Import transformed data
psql -U placebo_user -h localhost -d placebo_backend_db -f transformed-backend-data.sql
psql -U placebo_user -h localhost -d placebo_cms_db -f transformed-cms-data.sql
```

### Phase 3: Application Updates

#### 3.1 Update Environment Variables
Create `.env.production` files:
```bash
# backend/.env.production
DATABASE_TYPE=postgres
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE_USERNAME=placebo_user
DATABASE_PASSWORD=${POSTGRES_PASSWORD}
DATABASE_NAME=placebo_backend_db
DATABASE_SYNCHRONIZE=false

# cms/cms/.env.production
DATABASE_CLIENT=postgres
DATABASE_HOST=postgres
DATABASE_PORT=5432
DATABASE_NAME=placebo_cms_db
DATABASE_USERNAME=placebo_user
DATABASE_PASSWORD=${POSTGRES_PASSWORD}
DATABASE_SSL=false
```

#### 3.2 Update Docker Configuration
Update `docker-compose.yml` to use PostgreSQL for both services.

### Phase 4: Testing

#### 4.1 Local Testing with Docker Compose
```bash
# Start services with PostgreSQL
docker-compose up -d postgres backend cms frontend

# Run data migration
./scripts/migrate-data.sh

# Test endpoints
curl http://localhost:3000/health
curl http://localhost:1337/_health
```

#### 4.2 Data Validation
```sql
-- Verify data counts match
SELECT 'Backend Articles', COUNT(*) FROM articles
UNION ALL
SELECT 'CMS Content Types', COUNT(*) FROM strapi_content_types;

-- Verify relationships
SELECT a.title, COUNT(c.id) as comment_count
FROM articles a
LEFT JOIN comments c ON a.id = c.article_id
GROUP BY a.id;
```

### Phase 5: Production Deployment

#### 5.1 Create Migration Script
```bash
#!/bin/bash
# scripts/deploy-migration.sh

set -e

echo "Starting database migration..."

# Backup existing PostgreSQL data
pg_dump -U placebo_user -h ${PRODUCTION_DB_HOST} -d placebo_backend_db > backup-$(date +%Y%m%d).sql

# Run migrations
npm run typeorm:migration:run

# Verify migration
npm run typeorm:query "SELECT version_num FROM typeorm_migrations ORDER BY version_num DESC LIMIT 1;"

echo "Migration completed successfully!"
```

#### 5.2 Rollback Plan
```bash
#!/bin/bash
# scripts/rollback-migration.sh

set -e

echo "Starting rollback..."

# Restore from backup
psql -U placebo_user -h ${PRODUCTION_DB_HOST} -d placebo_backend_db -f backup-${BACKUP_DATE}.sql

# Revert environment variables
export DATABASE_TYPE=sqlite
export DATABASE_NAME=./data.db

echo "Rollback completed!"
```

## Migration Tools

### 1. SQLite to PostgreSQL Converter
```python
# scripts/sqlite_to_postgres.py
import sqlite3
import psycopg2
import os

def migrate_table(sqlite_conn, pg_conn, table_name):
    # Read from SQLite
    cursor_sqlite = sqlite_conn.cursor()
    cursor_sqlite.execute(f"SELECT * FROM {table_name}")
    rows = cursor_sqlite.fetchall()
    
    # Get column names
    cursor_sqlite.execute(f"PRAGMA table_info({table_name})")
    columns = [col[1] for col in cursor_sqlite.fetchall()]
    
    # Insert into PostgreSQL
    cursor_pg = pg_conn.cursor()
    placeholders = ', '.join(['%s'] * len(columns))
    columns_str = ', '.join(columns)
    
    for row in rows:
        cursor_pg.execute(
            f"INSERT INTO {table_name} ({columns_str}) VALUES ({placeholders})",
            row
        )
    
    pg_conn.commit()
```

### 2. Data Validation Script
```python
# scripts/validate_migration.py
def validate_counts(sqlite_conn, pg_conn, table_name):
    cursor_sqlite = sqlite_conn.cursor()
    cursor_sqlite.execute(f"SELECT COUNT(*) FROM {table_name}")
    sqlite_count = cursor_sqlite.fetchone()[0]
    
    cursor_pg = pg_conn.cursor()
    cursor_pg.execute(f"SELECT COUNT(*) FROM {table_name}")
    pg_count = cursor_pg.fetchone()[0]
    
    return sqlite_count == pg_count
```

## Timeline

### Week 1: Preparation
- Update database configurations
- Create migration scripts
- Set up PostgreSQL locally

### Week 2: Testing
- Test migration locally
- Validate data integrity
- Performance testing

### Week 3: Staging Deployment
- Deploy to staging environment
- User acceptance testing
- Fix any issues

### Week 4: Production Deployment
- Schedule maintenance window
- Execute migration
- Monitor performance
- Rollback if needed

## Risk Mitigation

### High Risks:
1. **Data loss**: Maintain multiple backups
2. **Downtime**: Schedule during low-traffic hours
3. **Performance issues**: Monitor closely after migration

### Mitigation Strategies:
1. Complete backup before migration
2. Gradual rollout with canary deployment
3. Performance monitoring for 48 hours post-migration

## Success Criteria
1. All data migrated without loss
2. Application functionality unchanged
3. Performance equal or better than SQLite
4. Zero downtime during migration
5. All tests passing post-migration

## Post-Migration Tasks
1. Update documentation
2. Remove SQLite dependencies
3. Set up PostgreSQL monitoring
4. Schedule regular backups
5. Update deployment scripts