Spaces:
Running
Running
| # Webapp entrypoint script - restores from S3 and runs database migrations before starting Gunicorn | |
| set -e | |
| echo "[ENTRYPOINT] Checking for S3 restore..." | |
| # Restore database from S3 if enabled (Feature 015) | |
| python3 <<'RESTORE_PYEOF' | |
| import os | |
| import sys | |
| # Add src directory to Python path | |
| sys.path.insert(0, '/app') | |
| try: | |
| from src.services.s3_restore import restore_on_startup | |
| result = restore_on_startup() | |
| print(f"[S3_RESTORE] Result: {result.value}") | |
| except Exception as e: | |
| print(f"[S3_RESTORE] Failed (non-fatal): {e}") | |
| # Continue startup even if restore fails | |
| RESTORE_PYEOF | |
| echo "[ENTRYPOINT] Running database migrations..." | |
| # Run Python migration script | |
| python3 <<'PYEOF' | |
| import sqlite3 | |
| import os | |
| DB_PATH = os.environ.get('DATABASE_PATH', '/app/data/contacts.db') | |
| MIGRATIONS_DIR = '/app/migrations' | |
| print(f"[MIGRATION] Connecting to database: {DB_PATH}") | |
| conn = sqlite3.connect(DB_PATH) | |
| cursor = conn.cursor() | |
| # Step 1: Check if contact_sessions table exists | |
| cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='contact_sessions'") | |
| table_exists = cursor.fetchone() is not None | |
| if not table_exists: | |
| print("[MIGRATION] Initial database - creating tables from 001_create_tables.sql") | |
| try: | |
| with open(f'{MIGRATIONS_DIR}/001_create_tables.sql', 'r') as f: | |
| schema_sql = f.read() | |
| cursor.executescript(schema_sql) | |
| conn.commit() | |
| print(" β Created user_profiles table") | |
| print(" β Created contact_sessions table") | |
| print(" β Created indexes") | |
| except Exception as e: | |
| print(f" β Failed to create initial schema: {e}") | |
| conn.rollback() | |
| raise | |
| # Step 2: Check if normalized_name column exists (producer columns migration) | |
| cursor.execute("PRAGMA table_info(contact_sessions)") | |
| columns = [row[1] for row in cursor.fetchall()] | |
| # Step 2a: Add contact_id column if missing (v2 API alignment) | |
| if 'contact_id' not in columns: | |
| print("[MIGRATION] Applying migration: Add contact_id column") | |
| try: | |
| cursor.execute("ALTER TABLE contact_sessions ADD COLUMN contact_id VARCHAR(255) NOT NULL DEFAULT ''") | |
| print(" β Added contact_id column") | |
| except Exception as e: | |
| print(f" β contact_id: {e}") | |
| try: | |
| cursor.execute("UPDATE contact_sessions SET contact_id = session_id WHERE contact_id = ''") | |
| print(f" β Backfilled {cursor.rowcount} existing contact_id values") | |
| except Exception as e: | |
| print(f" β backfill contact_id: {e}") | |
| try: | |
| cursor.execute("CREATE INDEX IF NOT EXISTS idx_contact_sessions_contact_id ON contact_sessions(contact_id)") | |
| print(" β Created index idx_contact_sessions_contact_id") | |
| except Exception as e: | |
| print(f" β index: {e}") | |
| conn.commit() | |
| print("[MIGRATION] contact_id migration complete") | |
| # Refresh columns list after contact_id migration | |
| cursor.execute("PRAGMA table_info(contact_sessions)") | |
| columns = [row[1] for row in cursor.fetchall()] | |
| if 'normalized_name' not in columns: | |
| print("[MIGRATION] Applying migration: Add producer-related columns") | |
| try: | |
| cursor.execute("ALTER TABLE contact_sessions ADD COLUMN normalized_name TEXT") | |
| print(" β Added normalized_name column") | |
| except Exception as e: | |
| print(f" β normalized_name: {e}") | |
| try: | |
| cursor.execute("ALTER TABLE contact_sessions ADD COLUMN sequence_number INTEGER DEFAULT 1") | |
| print(" β Added sequence_number column") | |
| except Exception as e: | |
| print(f" β sequence_number: {e}") | |
| try: | |
| cursor.execute("ALTER TABLE contact_sessions ADD COLUMN producer_id TEXT") | |
| print(" β Added producer_id column") | |
| except Exception as e: | |
| print(f" β producer_id: {e}") | |
| try: | |
| cursor.execute("CREATE INDEX IF NOT EXISTS idx_contact_sessions_producer ON contact_sessions(user_id, normalized_name)") | |
| print(" β Created index idx_contact_sessions_producer") | |
| except Exception as e: | |
| print(f" β index: {e}") | |
| try: | |
| cursor.execute(""" | |
| UPDATE contact_sessions | |
| SET | |
| normalized_name = LOWER(TRIM(contact_name)), | |
| sequence_number = 1, | |
| producer_id = user_id || '_' || LOWER(TRIM(contact_name)) || '_1' | |
| WHERE normalized_name IS NULL | |
| """) | |
| print(f" β Backfilled {cursor.rowcount} existing rows") | |
| except Exception as e: | |
| print(f" β backfill: {e}") | |
| conn.commit() | |
| print("[MIGRATION] Migration complete") | |
| else: | |
| print("[MIGRATION] Schema already up-to-date (normalized_name column exists)") | |
| conn.close() | |
| PYEOF | |
| echo "[ENTRYPOINT] Starting Gunicorn..." | |
| # Start Gunicorn with the provided arguments | |
| exec gunicorn -w 1 -b 0.0.0.0:7860 --timeout 120 --graceful-timeout 120 src.app:app | |