date('c'), 'source'=>'opus5-plan-registry']; $PG_DSN = 'pgsql:host=10.1.0.3;port=5432;dbname=adx_system;user=admin;password=admin123'; try { $db = new PDO($PG_DSN, null, null, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT=>5]); } catch (Throwable $e) { http_response_code(500); echo json_encode(['err'=>'pg_connect', 'msg'=>$e->getMessage()]); exit; } $raw = file_get_contents('php://input'); $d = json_decode($raw, true) ?: []; $action = $_GET['action'] ?? ($d['action'] ?? 'list'); if ($action === 'init') { try { $db->exec("CREATE TABLE IF NOT EXISTS admin.wevia_plans ( plan_id VARCHAR(64) PRIMARY KEY, name VARCHAR(255) NOT NULL, description TEXT, status VARCHAR(32) DEFAULT 'draft', priority INT DEFAULT 0, created_by VARCHAR(64) DEFAULT 'opus5', created_at TIMESTAMP DEFAULT NOW(), started_at TIMESTAMP, finished_at TIMESTAMP, metadata JSONB DEFAULT '{}'::jsonb )"); $db->exec("CREATE INDEX IF NOT EXISTS idx_plans_status ON admin.wevia_plans(status)"); $db->exec("CREATE INDEX IF NOT EXISTS idx_plans_created ON admin.wevia_plans(created_at DESC)"); $db->exec("CREATE TABLE IF NOT EXISTS admin.wevia_plan_steps ( step_id SERIAL PRIMARY KEY, plan_id VARCHAR(64) REFERENCES admin.wevia_plans(plan_id) ON DELETE CASCADE, step_order INT NOT NULL, step_name VARCHAR(255), step_type VARCHAR(32) DEFAULT 'action', action_url TEXT, action_method VARCHAR(8) DEFAULT 'POST', action_payload JSONB, depends_on INT[] DEFAULT '{}'::int[], status VARCHAR(32) DEFAULT 'pending', result TEXT, started_at TIMESTAMP, finished_at TIMESTAMP, task_id VARCHAR(64), retry_count INT DEFAULT 0 )"); $db->exec("CREATE INDEX IF NOT EXISTS idx_steps_plan ON admin.wevia_plan_steps(plan_id, step_order)"); $db->exec("CREATE INDEX IF NOT EXISTS idx_steps_status ON admin.wevia_plan_steps(status)"); $R['tables_ready'] = ['admin.wevia_plans', 'admin.wevia_plan_steps']; } catch (Throwable $e) { $R['err'] = $e->getMessage(); } $R['doctrine'] = '83 — plan registry PG tables (plans + plan_steps)'; echo json_encode($R, JSON_PRETTY_PRINT); exit; } if ($action === 'create') { $name = substr((string)($d['name'] ?? ''), 0, 255); $description = (string)($d['description'] ?? ''); $priority = (int)($d['priority'] ?? 0); $steps = $d['steps'] ?? []; // array of step definitions if (!$name) { http_response_code(400); echo json_encode(['err'=>'no_name']); exit; } $plan_id = 'plan_' . date('YmdHis') . '_' . bin2hex(random_bytes(3)); try { $db->beginTransaction(); $stmt = $db->prepare("INSERT INTO admin.wevia_plans (plan_id, name, description, priority, metadata) VALUES (?,?,?,?,?::jsonb)"); $stmt->execute([$plan_id, $name, $description, $priority, json_encode($d['metadata'] ?? [])]); $step_count = 0; foreach ($steps as $idx => $s) { $stmt = $db->prepare("INSERT INTO admin.wevia_plan_steps (plan_id, step_order, step_name, step_type, action_url, action_method, action_payload, depends_on) VALUES (?,?,?,?,?,?,?::jsonb,?::int[])"); $depends = '{' . implode(',', array_map('intval', $s['depends_on'] ?? [])) . '}'; $stmt->execute([ $plan_id, $idx + 1, substr((string)($s['name'] ?? "step_" . ($idx+1)), 0, 255), substr((string)($s['type'] ?? 'action'), 0, 32), (string)($s['url'] ?? ''), substr((string)($s['method'] ?? 'POST'), 0, 8), json_encode($s['payload'] ?? []), $depends ]); $step_count++; } $db->commit(); $R['plan_id'] = $plan_id; $R['steps_created'] = $step_count; } catch (Throwable $e) { if ($db->inTransaction()) $db->rollBack(); http_response_code(500); echo json_encode(['err'=>$e->getMessage()]); exit; } echo json_encode($R, JSON_PRETTY_PRINT); exit; } if ($action === 'list') { $limit = min(50, (int)($_GET['limit'] ?? 20)); $status_filter = preg_replace('/[^a-z_]/', '', $_GET['status'] ?? ''); $sql = "SELECT plan_id, name, status, priority, created_at, finished_at, (SELECT COUNT(*) FROM admin.wevia_plan_steps WHERE plan_id=p.plan_id) AS steps_total, (SELECT COUNT(*) FROM admin.wevia_plan_steps WHERE plan_id=p.plan_id AND status='done') AS steps_done FROM admin.wevia_plans p"; if ($status_filter) $sql .= " WHERE status='$status_filter'"; $sql .= " ORDER BY created_at DESC LIMIT $limit"; $rows = $db->query($sql)->fetchAll(PDO::FETCH_ASSOC); $R['count'] = count($rows); $R['plans'] = $rows; echo json_encode($R, JSON_PRETTY_PRINT); exit; } if ($action === 'get') { $pid = preg_replace('/[^a-z0-9_-]/i', '', $_GET['plan_id'] ?? $d['plan_id'] ?? ''); if (!$pid) { http_response_code(400); echo json_encode(['err'=>'no_plan_id']); exit; } $stmt = $db->prepare("SELECT * FROM admin.wevia_plans WHERE plan_id=?"); $stmt->execute([$pid]); $plan = $stmt->fetch(PDO::FETCH_ASSOC); if (!$plan) { http_response_code(404); echo json_encode(['err'=>'not_found']); exit; } $stmt = $db->prepare("SELECT * FROM admin.wevia_plan_steps WHERE plan_id=? ORDER BY step_order"); $stmt->execute([$pid]); $plan['steps'] = $stmt->fetchAll(PDO::FETCH_ASSOC); $R['plan'] = $plan; echo json_encode($R, JSON_PRETTY_PRINT); exit; } if ($action === 'update_status') { $pid = preg_replace('/[^a-z0-9_-]/i', '', (string)($d['plan_id'] ?? '')); $status = preg_replace('/[^a-z_]/', '', (string)($d['status'] ?? '')); if (!$pid || !$status) { http_response_code(400); echo json_encode(['err'=>'missing']); exit; } if ($status === 'running') { $db->prepare("UPDATE admin.wevia_plans SET status=?, started_at=COALESCE(started_at, NOW()) WHERE plan_id=?")->execute([$status, $pid]); } elseif (in_array($status, ['done','failed','cancelled'])) { $db->prepare("UPDATE admin.wevia_plans SET status=?, finished_at=NOW() WHERE plan_id=?")->execute([$status, $pid]); } else { $db->prepare("UPDATE admin.wevia_plans SET status=? WHERE plan_id=?")->execute([$status, $pid]); } $R['updated'] = $pid; $R['new_status'] = $status; echo json_encode($R, JSON_PRETTY_PRINT); exit; } if ($action === 'update_step') { $step_id = (int)($d['step_id'] ?? 0); $status = preg_replace('/[^a-z_]/', '', (string)($d['status'] ?? '')); $result = (string)($d['result'] ?? ''); if (!$step_id) { http_response_code(400); echo json_encode(['err'=>'no_step_id']); exit; } if ($status === 'running') { $db->prepare("UPDATE admin.wevia_plan_steps SET status=?, started_at=NOW() WHERE step_id=?")->execute([$status, $step_id]); } elseif (in_array($status, ['done','failed'])) { $db->prepare("UPDATE admin.wevia_plan_steps SET status=?, result=?, finished_at=NOW() WHERE step_id=?")->execute([$status, substr($result,0,5000), $step_id]); } $R['step_updated'] = $step_id; echo json_encode($R, JSON_PRETTY_PRINT); exit; } http_response_code(400); echo json_encode(['err'=>'unknown_action', 'available'=>['init','create','list','get','update_status','update_step']]);