#!/usr/bin/env python3 """Last-resort AppFloyo fix — runs all commands directly via SSH.""" import subprocess, time HOST = "allaun@100.92.88.64" def sh(cmd, timeout=60): r = subprocess.run(["ssh", "-o", "ConnectTimeout=10", HOST, cmd], capture_output=True, text=True, timeout=timeout) if r.stdout.strip(): print(r.stdout.strip()[:200]) if r.returncode != 0: err = r.stderr.strip()[:100] if err: print(f" (stderr: {err})") def run(cmd, timeout=60): return subprocess.run(["ssh", "-o", "ConnectTimeout=10", HOST, cmd], capture_output=True, text=True, timeout=timeout).returncode print("1. Postgres") run("podman restart arxiv-pg 2>/dev/null", timeout=15) time.sleep(10) run("pg_isready -h localhost", timeout=10) print("2. AppFloyo DB + Redis") sh("podman exec arxiv-pg psql -U postgres -c 'CREATE DATABASE appflowy' 2>/dev/null || true", timeout=15) sh("podman exec arxiv-pg psql -U postgres -d appflowy -c 'CREATE SCHEMA IF NOT EXISTS auth' 2>/dev/null", timeout=10) run("podman run -d --name redis --network host docker.io/library/redis:7-alpine 2>/dev/null", timeout=20) print("3. GoTrue init migration") init_sql = subprocess.run( ["podman", "run", "--rm", "docker.io/appflowyinc/gotrue:0.15.1", "cat", "/migrations/00_init_auth_schema.up.sql"], capture_output=True, text=True, timeout=15 ).stdout.replace("{{ index .Options \"Namespace\" }}", "auth") proc = subprocess.Popen( ["ssh", HOST, "podman exec -i arxiv-pg psql -U postgres -d appflowy -v ON_ERROR_STOP=1"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdout, stderr = proc.communicate(input=init_sql.encode(), timeout=60) print(f" Init: {stdout.decode()[:100] if stdout else 'ok'}") print("4. Mark all GoTrue migrations done") migs = subprocess.run( ["podman", "run", "--rm", "docker.io/appflowyinc/gotrue:0.15.1", "ls", "/migrations/"], capture_output=True, text=True, timeout=15 ) versions = sorted(set(f.split("_")[0] for f in migs.stdout.strip().split("\n") if f.endswith(".up.sql"))) for v in versions: run(f"podman exec arxiv-pg psql -U postgres -d appflowy -c \"INSERT INTO auth.schema_migrations (version) VALUES ('{v}') ON CONFLICT DO NOTHING\"", timeout=10) ct = run("podman exec arxiv-pg psql -U postgres -d appflowy -t -A -c 'SELECT COUNT(*) FROM auth.schema_migrations'", timeout=10) print(f" {len(versions)} versions, tracked") print("5. Pre-create one_time_tokens") subprocess.Popen( ["ssh", HOST, "podman exec -i arxiv-pg psql -U postgres -d appflowy"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE ).communicate( input=b"CREATE TABLE IF NOT EXISTS auth.one_time_tokens (id uuid PRIMARY KEY, user_id uuid, token_type text NOT NULL, token_hash text NOT NULL, expires_at timestamptz NOT NULL, created_at timestamptz NOT NULL DEFAULT now());", timeout=30 ) print("6. Start GoTrue") run("podman rm -f appflowy_gotrue_1 2>/dev/null", timeout=10) sh( 'podman run -d --name appflowy_gotrue_1 --network host ' '-e GOTRUE_ADMIN_EMAIL=admin@researchstack.info ' '-e GOTRUE_ADMIN_PASSWORD=admin123 ' '-e GOTRUE_DISABLE_SIGNUP=false ' '-e GOTRUE_SITE_URL=https://researchstack.info/appflowy ' '-e GOTRUE_URI_ALLOW_LIST=** ' '-e GOTRUE_JWT_SECRET=jwt_ ' '-e GOTRUE_JWT_EXP=3600 ' '-e GOTRUE_DB_DRIVER=postgres ' '-e API_EXTERNAL_URL=https://researchstack.info/appflowy/gotrue ' "-e DATABASE_URL='postgres://postgres:postgres@localhost:5432/appflowy' " '-e PORT=9999 ' '-e GOTRUE_MAILER_AUTOCONFIRM=true ' '-e GOTRUE_LOG_LEVEL=info ' '-e REDIS_ENABLED=true ' '-e REDIS_URL=redis://localhost:6379 ' 'docker.io/appflowyinc/gotrue:0.15.1', timeout=20 ) time.sleep(10) hc = subprocess.run(["ssh", "-o", "ConnectTimeout=5", HOST, "curl -s -o /dev/null -w '%{http_code}' http://localhost:9999/health"], capture_output=True, text=True, timeout=10) print(f" GoTrue: {hc.stdout.strip()}")