v2-exece-docs
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
|
||||
**Document ID:** 00C-igny8-production-migration
|
||||
**Phase:** Phase 0: Production Migration
|
||||
**Version:** 2.0
|
||||
**Version:** 2.1
|
||||
**Date:** 2026-03-23
|
||||
**Status:** In Progress
|
||||
**Source of Truth:** Codebase at `/data/app/igny8/`
|
||||
|
||||
**Related Docs:**
|
||||
- 00A: GitHub Repository Consolidation (completed)
|
||||
@@ -23,18 +24,29 @@
|
||||
**Project Name:** igny8-app
|
||||
**Compose File:** docker-compose.app.yml
|
||||
|
||||
#### Active Containers
|
||||
#### Active Containers (Verified from docker-compose.app.yml)
|
||||
|
||||
**App containers (7 in docker-compose.app.yml):**
|
||||
|
||||
| Container | Service | Port (Host:Container) | Technology |
|
||||
|-----------|---------|----------------------|------------|
|
||||
| igny8_backend | REST API | 8011:8010 | Django >=5.2.7 + Gunicorn (4 workers, 120s timeout) |
|
||||
| igny8_frontend | Web UI | 8021:5173 | Vite dev server (React ^19, Node 18) |
|
||||
| igny8_marketing_dev | Marketing site | 8023:5174 | Vite dev server |
|
||||
| igny8_celery_worker | Task worker | — | Celery (concurrency=4) |
|
||||
| igny8_celery_beat | Task scheduler | — | Celery Beat |
|
||||
| igny8_flower | Celery monitor | 5555:5555 | Flower |
|
||||
|
||||
**Shared infra containers (external to app compose, on igny8_net):**
|
||||
|
||||
| Container | Service | Port (Internal) | Technology |
|
||||
|-----------|---------|----------------|------------|
|
||||
| igny8_backend | REST API | 8010 | Django 4.2 + Gunicorn (4 workers, 120s timeout) |
|
||||
| igny8_frontend | Web UI | 5173 → 8021 | Vite dev server |
|
||||
| igny8_celery_worker | Task worker | N/A | Celery |
|
||||
| igny8_celery_beat | Task scheduler | N/A | Celery Beat |
|
||||
| igny8_postgres | Database | 5432 | PostgreSQL 16 |
|
||||
| igny8_redis | Cache/Broker | 6379 | Redis 7 (DB 0) |
|
||||
| postgres | Database | 5432 | PostgreSQL (version set by infra stack) |
|
||||
| redis | Cache/Broker | 6379 | Redis (DB 0 for production) |
|
||||
| caddy | Reverse proxy/SSL | 80, 443 | Caddy 2 |
|
||||
| marketing | Render service | 8023 | Custom service |
|
||||
| sites | Render service | 8024 | Custom service |
|
||||
| portainer | Docker management | 9000 | Portainer CE |
|
||||
| pgadmin | DB admin | 5050 | PgAdmin 4 |
|
||||
| filebrowser | File management | 8080 | FileBrowser |
|
||||
|
||||
#### Database
|
||||
- **Database Name:** igny8_db
|
||||
@@ -61,7 +73,7 @@
|
||||
- CELERY_BROKER_URL
|
||||
- Django DEBUG, ALLOWED_HOSTS
|
||||
|
||||
**Important:** AI integration keys stored in database (GlobalIntegrationSettings table), NOT in env vars.
|
||||
**Important:** AI integration keys stored in database (`IntegrationProvider` table: `igny8_integration_providers`, and `IntegrationSettings` table: `igny8_integration_settings`), NOT in env vars.
|
||||
|
||||
#### Networking
|
||||
- **Primary Domain:** app.igny8.com (frontend)
|
||||
@@ -77,9 +89,11 @@
|
||||
- **Backup Automation:** Cron jobs on old VPS (backup-db.sh, backup-full.sh)
|
||||
|
||||
#### Health Check
|
||||
- **Endpoint:** http://localhost:8010/api/v1/system/status/
|
||||
- **Expected Response:** 200 OK with system status JSON
|
||||
- **Endpoint:** http://localhost:8010/api/v1/system/status/ (inside container) or http://localhost:8011/api/v1/system/status/ (from host)
|
||||
- **Expected Response:** 200 OK with system status JSON (timestamp, system resources, database, Redis, Celery status)
|
||||
- **Permission:** AllowAny (public endpoint)
|
||||
- **Frequency:** Manual or via monitoring
|
||||
- **Docker healthcheck:** Configured in compose: 30s interval, 10s timeout, 3 retries
|
||||
|
||||
---
|
||||
|
||||
@@ -167,30 +181,60 @@ This migration is **not a direct cutover**. Instead, we run both VPS in parallel
|
||||
|
||||
The database schema itself does not change during migration. We use pg_dump and pg_restore to move the entire database from old VPS (PG 16) to new VPS (PG 18).
|
||||
|
||||
**Key Tables (not exhaustive):**
|
||||
- `users` — User accounts
|
||||
- `projects` — Projects/sites
|
||||
- `stripe_subscriptions` — Payment records
|
||||
- `integration_settings` — AI integration keys (GlobalIntegrationSettings)
|
||||
- `wordpress_sync_logs` — Plugin sync history
|
||||
- `celery_*` — Celery task tables
|
||||
**Key Tables (verified from codebase — all use `igny8_` prefix convention):**
|
||||
|
||||
| Table | Purpose |
|
||||
|-------|---------|
|
||||
| `igny8_users` | User accounts (AUTH_USER_MODEL) |
|
||||
| `igny8_tenants` | Multi-tenant accounts |
|
||||
| `igny8_sites` | Sites within accounts |
|
||||
| `igny8_subscriptions` | Subscription records |
|
||||
| `igny8_plans` | Plan definitions |
|
||||
| `igny8_content` | Content items |
|
||||
| `igny8_tasks` | Writer tasks |
|
||||
| `igny8_clusters` | Keyword clusters |
|
||||
| `igny8_keywords` | Keywords |
|
||||
| `igny8_content_ideas` | Content ideas |
|
||||
| `igny8_images` | Generated images |
|
||||
| `igny8_invoices` | Billing invoices |
|
||||
| `igny8_payments` | Payment records |
|
||||
| `igny8_webhook_events` | Stripe/PayPal webhooks |
|
||||
| `igny8_site_integrations` | WordPress site connections |
|
||||
| `igny8_sync_events` | WordPress sync history |
|
||||
| `igny8_publishing_records` | Publish records |
|
||||
| `igny8_ai_task_logs` | AI task audit trail |
|
||||
| `igny8_automation_configs` | Automation settings |
|
||||
| `igny8_automation_runs` | Automation run history |
|
||||
| `plugins` / `plugin_versions` / `plugin_installations` / `plugin_downloads` | Plugin system |
|
||||
| `igny8_integration_providers` / `igny8_integration_settings` | AI/payment provider keys |
|
||||
|
||||
**Note:** There is NO `stripe_subscriptions` table, NO `wordpress_sync_logs` table, NO `GlobalIntegrationSettings` table. These were errors in earlier doc versions.
|
||||
|
||||
**Important:** Do NOT manually migrate tables. Use pg_dump/pg_restore with custom format.
|
||||
|
||||
### 3.2 Health Check API
|
||||
|
||||
**Endpoint:** `GET http://localhost:8010/api/v1/system/status/`
|
||||
**Expected Response:**
|
||||
**Endpoint:** `GET /api/v1/system/status/` (AllowAny — no auth required)
|
||||
|
||||
**Actual response format** (verified from `igny8_core/modules/system/views.py:system_status`):
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "1.8.4",
|
||||
"database": "connected",
|
||||
"redis": "connected",
|
||||
"celery": "ok"
|
||||
"timestamp": "2026-03-23T12:00:00.000000+00:00",
|
||||
"system": {
|
||||
"cpu": {"usage_percent": 12.5, "cores": 4, "status": "healthy"},
|
||||
"memory": {"total_gb": 8.0, "used_gb": 3.2, "available_gb": 4.8, "usage_percent": 40.0, "status": "healthy"},
|
||||
"disk": {"total_gb": 100.0, "used_gb": 35.0, "free_gb": 65.0, "usage_percent": 35.0, "status": "healthy"}
|
||||
},
|
||||
"database": {"connected": true, "version": "PostgreSQL 16.x ...", "size": "256 MB", "active_connections": 5, "status": "healthy"},
|
||||
"redis": {"connected": true, "status": "healthy", "info": {}},
|
||||
"celery": {"workers": ["celery@igny8_celery_worker"], "worker_count": 1, "tasks": {"active": 0, "scheduled": 0, "reserved": 0}, "status": "healthy"},
|
||||
"processes": {},
|
||||
"modules": {}
|
||||
}
|
||||
```
|
||||
|
||||
**Healthy indicators:** All `status` fields should be `"healthy"`, `database.connected` and `redis.connected` should be `true`, `celery.worker_count` should be ≥ 1.
|
||||
|
||||
Use this endpoint to verify both old and new VPS health before/after migration.
|
||||
|
||||
---
|
||||
@@ -222,11 +266,11 @@ git checkout main # or appropriate branch
|
||||
cp .env.example .env
|
||||
|
||||
# Update .env for new VPS:
|
||||
# - DB_HOST=igny8_postgres (Docker internal hostname)
|
||||
# - DB_HOST=postgres (Docker service name on igny8_net — infra container, not app container)
|
||||
# - DB_NAME=igny8_db
|
||||
# - DB_USER=igny8
|
||||
# - DB_PASSWORD=<secure password>
|
||||
# - REDIS_HOST=igny8_redis
|
||||
# - REDIS_URL=redis://redis:6379/0 (Redis is also an infra container on igny8_net)
|
||||
# - SECRET_KEY=<generate new>
|
||||
# - ALLOWED_HOSTS=test-app.igny8.com,test-api.igny8.com,app.igny8.com,api.igny8.com,igny8.com
|
||||
|
||||
@@ -282,7 +326,7 @@ PGPASSWORD=<db-password> pg_restore --format=custom \
|
||||
/tmp/igny8_db_backup.dump
|
||||
|
||||
# Verify restore completed
|
||||
PGPASSWORD=<db-password> psql --host=localhost --username=igny8 --dbname=igny8_db -c "SELECT COUNT(*) FROM users;"
|
||||
PGPASSWORD=<db-password> psql --host=localhost --username=igny8 --dbname=igny8_db -c "SELECT COUNT(*) FROM igny8_users;"
|
||||
|
||||
# Run ANALYZE on all tables to update statistics
|
||||
PGPASSWORD=<db-password> psql --host=localhost --username=igny8 --dbname=igny8_db -c "ANALYZE;"
|
||||
@@ -315,16 +359,15 @@ On new VPS:
|
||||
```bash
|
||||
cd /data/app/igny8
|
||||
|
||||
# Copy docker-compose file (create if needed)
|
||||
# Ensure it contains:
|
||||
# - igny8_backend (Django)
|
||||
# - igny8_frontend (Vite)
|
||||
# - igny8_celery_worker
|
||||
# - igny8_celery_beat
|
||||
# - igny8_postgres (PostgreSQL 18)
|
||||
# - igny8_redis
|
||||
# - caddy
|
||||
# - marketing, sites (if needed)
|
||||
# docker-compose.app.yml should contain these app containers:
|
||||
# - igny8_backend (Django + Gunicorn)
|
||||
# - igny8_frontend (Vite/React)
|
||||
# - igny8_marketing_dev (Vite marketing site)
|
||||
# - igny8_celery_worker (Celery)
|
||||
# - igny8_celery_beat (Celery Beat)
|
||||
# - igny8_flower (Flower monitor)
|
||||
# NOTE: postgres, redis, caddy are INFRA containers — NOT in app compose.
|
||||
# They must already be running on igny8_net (provisioned in 00B).
|
||||
|
||||
# Build and start
|
||||
docker compose -f docker-compose.app.yml build
|
||||
@@ -355,22 +398,14 @@ curl -I https://test-api.igny8.com
|
||||
#### Step 1.7: Run Health Checks on Test Subdomains
|
||||
|
||||
```bash
|
||||
# Health check via test API subdomain
|
||||
curl -H "Host: test-api.igny8.com" http://localhost:8010/api/v1/system/status/
|
||||
# Health check via test API subdomain (port 8011 is the host-mapped backend port)
|
||||
curl -H "Host: test-api.igny8.com" http://localhost:8011/api/v1/system/status/
|
||||
|
||||
# Or if DNS is live
|
||||
curl https://test-api.igny8.com/api/v1/system/status/
|
||||
```
|
||||
|
||||
**Expected Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"version": "1.8.4",
|
||||
"database": "connected",
|
||||
"redis": "connected",
|
||||
"celery": "ok"
|
||||
}
|
||||
**Verify response:** `database.connected` = true, `redis.connected` = true, `celery.worker_count` ≥ 1, all `status` fields = "healthy". See Section 3.2 for full response format.
|
||||
```
|
||||
|
||||
#### Step 1.8: Manual Testing on Test Subdomains
|
||||
|
||||
Reference in New Issue
Block a user