docker implementation
This commit is contained in:
1 parent
7c7bb45446
commit
0c2433cac6
26 files changed
+2200
-13
No files matched your search
@@ -0,0 +1,44 @@
|
||||
-- PostgreSQL initialization script for Placebo.mk development
|
||||
-- Creates separate databases for backend and CMS
|
||||
|
||||
-- Create databases if they don't exist
|
||||
SELECT 'CREATE DATABASE placebo_backend_db'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'placebo_backend_db')\gexec
|
||||
|
||||
SELECT 'CREATE DATABASE placebo_cms_db'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'placebo_cms_db')\gexec
|
||||
|
||||
-- Create user if it doesn't exist
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'placebo_user') THEN
|
||||
CREATE USER placebo_user WITH PASSWORD 'placebo_password';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Grant privileges
|
||||
GRANT ALL PRIVILEGES ON DATABASE placebo_backend_db TO placebo_user;
|
||||
GRANT ALL PRIVILEGES ON DATABASE placebo_cms_db TO placebo_user;
|
||||
|
||||
-- Create extensions (useful for some applications)
|
||||
\c placebo_backend_db
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
\c placebo_cms_db
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
|
||||
|
||||
-- Set search path for convenience
|
||||
ALTER DATABASE placebo_backend_db SET search_path TO public;
|
||||
ALTER DATABASE placebo_cms_db SET search_path TO public;
|
||||
|
||||
-- Output status
|
||||
SELECT 'PostgreSQL initialization complete' AS status;
|
||||
SELECT
|
||||
datname as database,
|
||||
pg_size_pretty(pg_database_size(datname)) as size,
|
||||
(SELECT count(*) FROM pg_tables WHERE schemaname = 'public') as tables_count
|
||||
FROM pg_database
|
||||
WHERE datname IN ('placebo_backend_db', 'placebo_cms_db');
|
||||
@@ -0,0 +1,297 @@
|
||||
# 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
|
||||
Executable
+147
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Test script for Placebo.mk Docker setup
|
||||
|
||||
set -e
|
||||
|
||||
echo "🧪 Testing Placebo.mk Docker setup..."
|
||||
|
||||
# Check if docker-compose is available
|
||||
if ! command -v docker-compose &> /dev/null; then
|
||||
echo "⚠️ docker-compose not found, using docker compose"
|
||||
DOCKER_COMPOSE="docker compose"
|
||||
else
|
||||
DOCKER_COMPOSE="docker-compose"
|
||||
fi
|
||||
|
||||
# Create environment files if they don't exist
|
||||
echo "📝 Creating environment files..."
|
||||
|
||||
# Backend .env
|
||||
if [ ! -f backend/.env ]; then
|
||||
cat > backend/.env << EOF
|
||||
# Backend Environment Variables
|
||||
NODE_ENV=production
|
||||
DATABASE_TYPE=postgres
|
||||
DATABASE_HOST=postgres
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_USERNAME=placebo_user
|
||||
DATABASE_PASSWORD=placebo_password
|
||||
DATABASE_NAME=placebo_db
|
||||
DATABASE_SYNCHRONIZE=false
|
||||
DATABASE_LOGGING=false
|
||||
JWT_SECRET=your-jwt-secret-key-change-in-production
|
||||
JWT_EXPIRATION=3600
|
||||
CORS_ORIGIN=http://localhost:5173,http://localhost:3001
|
||||
PORT=3000
|
||||
EOF
|
||||
echo "✅ Created backend/.env"
|
||||
fi
|
||||
|
||||
# Frontend .env
|
||||
if [ ! -f frontend/.env ]; then
|
||||
cat > frontend/.env << EOF
|
||||
# Frontend Environment Variables
|
||||
NODE_ENV=production
|
||||
VITE_API_URL=http://localhost:3000
|
||||
VITE_CMS_URL=http://localhost:1337
|
||||
EOF
|
||||
echo "✅ Created frontend/.env"
|
||||
fi
|
||||
|
||||
# CMS .env
|
||||
if [ ! -f cms/cms/.env ]; then
|
||||
cat > cms/cms/.env << EOF
|
||||
# CMS Environment Variables
|
||||
NODE_ENV=production
|
||||
DATABASE_CLIENT=postgres
|
||||
DATABASE_HOST=postgres
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_NAME=placebo_db
|
||||
DATABASE_USERNAME=placebo_user
|
||||
DATABASE_PASSWORD=placebo_password
|
||||
DATABASE_SSL=false
|
||||
JWT_SECRET=your-jwt-secret-key-change-in-production
|
||||
ADMIN_JWT_SECRET=your-admin-jwt-secret-key-change-in-production
|
||||
APP_KEYS=your-app-keys-change-in-production
|
||||
API_TOKEN_SALT=your-api-token-salt-change-in-production
|
||||
TRANSFER_TOKEN_SALT=your-transfer-token-salt-change-in-production
|
||||
CORS_ORIGIN=http://localhost:5173,http://localhost:3001
|
||||
PORT=1337
|
||||
EOF
|
||||
echo "✅ Created cms/cms/.env"
|
||||
fi
|
||||
|
||||
# Create database initialization script
|
||||
mkdir -p scripts
|
||||
cat > scripts/init-db.sql << EOF
|
||||
-- Create separate databases for backend and CMS
|
||||
CREATE DATABASE placebo_backend_db;
|
||||
CREATE DATABASE placebo_cms_db;
|
||||
|
||||
-- Grant privileges
|
||||
GRANT ALL PRIVILEGES ON DATABASE placebo_backend_db TO placebo_user;
|
||||
GRANT ALL PRIVILEGES ON DATABASE placebo_cms_db TO placebo_user;
|
||||
EOF
|
||||
echo "✅ Created database initialization script"
|
||||
|
||||
echo "🐳 Building Docker images..."
|
||||
$DOCKER_COMPOSE build
|
||||
|
||||
echo "🚀 Starting services..."
|
||||
$DOCKER_COMPOSE up -d
|
||||
|
||||
echo "⏳ Waiting for services to be healthy..."
|
||||
sleep 30
|
||||
|
||||
echo "📊 Checking service status..."
|
||||
$DOCKER_COMPOSE ps
|
||||
|
||||
echo "🔍 Testing service connectivity..."
|
||||
|
||||
# Test PostgreSQL
|
||||
echo "Testing PostgreSQL..."
|
||||
if docker exec placebo-postgres pg_isready -U placebo_user -d placebo_db; then
|
||||
echo "✅ PostgreSQL is healthy"
|
||||
else
|
||||
echo "❌ PostgreSQL health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test Backend
|
||||
echo "Testing Backend API..."
|
||||
if curl -f http://localhost:3000/health > /dev/null 2>&1; then
|
||||
echo "✅ Backend API is healthy"
|
||||
else
|
||||
echo "❌ Backend API health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test CMS
|
||||
echo "Testing CMS..."
|
||||
if curl -f http://localhost:1337/_health > /dev/null 2>&1; then
|
||||
echo "✅ CMS is healthy"
|
||||
else
|
||||
echo "❌ CMS health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test Frontend
|
||||
echo "Testing Frontend..."
|
||||
if curl -f http://localhost:3001 > /dev/null 2>&1; then
|
||||
echo "✅ Frontend is serving"
|
||||
else
|
||||
echo "❌ Frontend health check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🎉 All tests passed! Docker setup is working correctly."
|
||||
echo ""
|
||||
echo "Services are running at:"
|
||||
echo " Frontend: http://localhost:3001"
|
||||
echo " Backend API: http://localhost:3000"
|
||||
echo " CMS Admin: http://localhost:1337/admin"
|
||||
echo ""
|
||||
echo "To stop services: docker-compose down"
|
||||
echo "To view logs: docker-compose logs -f"
|
||||
Reference in new issue
Block a user