#!/usr/bin/env bash set -euo pipefail DB_FILE="/opt/appfactory/data/appfactory/appfactory.db" if [ ! -f "$DB_FILE" ]; then echo "Missing database: $DB_FILE" exit 1 fi python3 - "$DB_FILE" <<'PY' import sqlite3 import sys db_file = sys.argv[1] con = sqlite3.connect(db_file) columns = [row[1] for row in con.execute("PRAGMA table_info(apps)").fetchall()] def add_column(name: str, definition: str): if name not in columns: con.execute(f"ALTER TABLE apps ADD COLUMN {name} {definition}") add_column("description", "TEXT") add_column("owner", "TEXT") add_column("template", "TEXT") add_column("runtime", "TEXT") add_column("repository_url", "TEXT") add_column("repository_name", "TEXT") add_column("default_branch", "TEXT NOT NULL DEFAULT 'main'") add_column("domain", "TEXT") add_column("health_url", "TEXT") add_column("container_port", "INTEGER") add_column("is_public", "INTEGER NOT NULL DEFAULT 1") add_column("is_enabled", "INTEGER NOT NULL DEFAULT 1") con.execute(""" CREATE TABLE IF NOT EXISTS app_templates ( id TEXT PRIMARY KEY, name TEXT NOT NULL, runtime TEXT NOT NULL, language TEXT NOT NULL, description TEXT, default_port INTEGER, default_health_path TEXT NOT NULL DEFAULT '/health', is_enabled INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ) """) con.execute(""" CREATE TABLE IF NOT EXISTS app_variables ( id INTEGER PRIMARY KEY AUTOINCREMENT, app_id TEXT NOT NULL, key TEXT NOT NULL, value TEXT, is_secret INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE(app_id, key) ) """) con.execute(""" CREATE INDEX IF NOT EXISTS idx_app_variables_app_id ON app_variables(app_id) """) templates = [ ( "fastapi", "FastAPI", "python", "python", "Python FastAPI service", 8000, "/health", ), ( "dotnet-api", ".NET API", "dotnet", "csharp", ".NET Web API service", 8080, "/health", ), ( "dotnet-worker", ".NET Worker", "dotnet", "csharp", ".NET background worker service", None, "/health", ), ( "nodejs-ts", "Node.js TypeScript", "node", "typescript", "Node.js service written in TypeScript", 3000, "/health", ), ( "static-site", "Static Site", "static", "html", "Static website served by gateway", 80, "/", ), ] con.executemany( """ INSERT INTO app_templates ( id, name, runtime, language, description, default_port, default_health_path ) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = excluded.name, runtime = excluded.runtime, language = excluded.language, description = excluded.description, default_port = excluded.default_port, default_health_path = excluded.default_health_path, updated_at = CURRENT_TIMESTAMP """, templates, ) con.execute(""" UPDATE apps SET runtime = COALESCE(runtime, language), template = COALESCE(template, CASE WHEN language = 'python' THEN 'fastapi' ELSE language END), repository_name = COALESCE(repository_name, id), health_url = COALESCE(health_url, '/health'), container_port = COALESCE(container_port, 8000), is_public = COALESCE(is_public, 1), is_enabled = COALESCE(is_enabled, 1) """) con.commit() con.close() print("App metadata migration completed.") PY