docker implementation

This commit is contained in:
dimitar committed 2026-02-01 13:32:37 +01:00
1 parent 7c7bb45446
commit 0c2433cac6
26 files changed
+2200 -13

No files matched your search

+44
View File
@@ -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');
+297
View File
@@ -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
+147
View File
@@ -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"