import { pool } from '../db.js'; /** * Проверка прав доступа пользователя к сценарию */ export async function getUserScenarioPermission(userId, scenarioId) { const query = ` SELECT can_start, can_execute, can_view_results FROM uno_bff.scenario_permissions WHERE user_id = $1 AND scenario_id = $2 `; const result = await pool.query(query, [userId, scenarioId]); return result.rows[0] || null; } /** * Получить сценарий по ID */ export async function getScenarioById(scenarioId) { const query = ` SELECT scenario_id, name, description, status, is_public, start_workflow_key, created_at, updated_at FROM uno_bff.scenarios WHERE scenario_id = $1 `; const result = await pool.query(query, [scenarioId]); return result.rows[0] || null; } /** * Получить шаг сценария по ID */ export async function getScenarioStep(scenarioId, stepId) { const query = ` SELECT scenario_id, step_id, name, description, step_order, status, step_workflow_key, is_terminal, input_schema, output_schema, created_at, updated_at FROM uno_bff.scenario_steps WHERE scenario_id = $1 AND step_id = $2 `; const result = await pool.query(query, [scenarioId, stepId]); return result.rows[0] || null; } /** * Получить первый шаг сценария */ export async function getFirstScenarioStep(scenarioId) { const query = ` SELECT scenario_id, step_id, name, description, step_order, status, step_workflow_key, is_terminal, input_schema, output_schema FROM uno_bff.scenario_steps WHERE scenario_id = $1 AND status = 'active' ORDER BY step_order ASC LIMIT 1 `; const result = await pool.query(query, [scenarioId]); return result.rows[0] || null; } /** * Создать запись generation */ export async function createGeneration({ userId, scenarioId, authSessionId, requestPayload, currentStepId }) { const query = ` INSERT INTO uno_bff.generations (user_id, scenario_id, auth_session_id, status, request_payload, current_step_id) VALUES ($1, $2, $3, 'running', $4, $5) RETURNING generation_uuid, user_id, scenario_id, auth_session_id, status, current_step_id, request_payload, started_at `; const result = await pool.query(query, [userId, scenarioId, authSessionId, JSON.stringify(requestPayload), currentStepId]); return result.rows[0]; } /** * Получить generation по UUID */ export async function getGenerationByUuid(generationUuid) { const query = ` SELECT generation_uuid, user_id, scenario_id, auth_session_id, status, current_step_id, request_payload, result_payload, last_error_payload, external_run_id, started_at, finished_at FROM uno_bff.generations WHERE generation_uuid = $1 `; const result = await pool.query(query, [generationUuid]); return result.rows[0] || null; } /** * Обновить generation (после выполнения шага) */ export async function updateGeneration(generationUuid, updates) { const fields = []; const values = []; let idx = 1; if (updates.status !== undefined) { fields.push(`status = $${idx++}`); values.push(updates.status); } if (updates.currentStepId !== undefined) { fields.push(`current_step_id = $${idx++}`); values.push(updates.currentStepId); } if (updates.resultPayload !== undefined) { fields.push(`result_payload = $${idx++}`); values.push(JSON.stringify(updates.resultPayload)); } if (updates.lastErrorPayload !== undefined) { fields.push(`last_error_payload = $${idx++}`); values.push(JSON.stringify(updates.lastErrorPayload)); } if (updates.externalRunId !== undefined) { fields.push(`external_run_id = $${idx++}`); values.push(updates.externalRunId); } if (updates.finishedAt !== undefined) { fields.push(`finished_at = $${idx++}`); values.push(updates.finishedAt); } if (fields.length === 0) { return getGenerationByUuid(generationUuid); } values.push(generationUuid); const query = ` UPDATE uno_bff.generations SET ${fields.join(', ')}, updated_at = now() WHERE generation_uuid = $${idx} RETURNING generation_uuid, user_id, scenario_id, status, current_step_id, request_payload, result_payload, external_run_id `; const result = await pool.query(query, values); return result.rows[0]; } /** * Обновить generation_step * Используется n8n workflow для обновления статуса шага */ export async function updateGenerationStepByUuid(generationUuid, stepId, updates) { const fields = []; const values = []; let idx = 1; if (updates.status !== undefined) { fields.push(`status = $${idx++}`); values.push(updates.status); } if (updates.responsePayload !== undefined) { fields.push(`response_payload = $${idx++}`); values.push(JSON.stringify(updates.responsePayload)); } if (updates.errorPayload !== undefined) { fields.push(`error_payload = $${idx++}`); values.push(JSON.stringify(updates.errorPayload)); } if (updates.startedAt !== undefined) { fields.push(`started_at = $${idx++}`); values.push(updates.startedAt); } if (updates.finishedAt !== undefined) { fields.push(`finished_at = $${idx++}`); values.push(updates.finishedAt); } if (fields.length === 0) { return getGenerationStep(generationUuid, stepId); } values.push(generationUuid, stepId); const query = ` UPDATE uno_bff.generation_steps SET ${fields.join(', ')}, updated_at = now() WHERE generation_uuid = $${idx} AND step_id = $${idx + 1} RETURNING id, generation_uuid, scenario_id, step_id, status, request_payload, response_payload `; const result = await pool.query(query, values); return result.rows[0]; } /** * Получить generation_step */ export async function getGenerationStep(generationUuid, stepId) { const query = ` SELECT id, generation_uuid, scenario_id, step_id, step_order, status, request_payload, response_payload, error_payload FROM uno_bff.generation_steps WHERE generation_uuid = $1 AND step_id = $2 `; const result = await pool.query(query, [generationUuid, stepId]); return result.rows[0] || null; } /** * Получить generation по UUID с проверкой принадлежности пользователю */ export async function getGenerationByUuidForUser(generationUuid, userId) { const query = ` SELECT g.generation_uuid, g.user_id, g.scenario_id, g.auth_session_id, g.status, g.current_step_id, g.request_payload, g.result_payload, g.last_error_payload, g.external_run_id, g.started_at, g.finished_at, s.name as scenario_name FROM uno_bff.generations g LEFT JOIN uno_bff.scenarios s ON g.scenario_id = s.scenario_id WHERE g.generation_uuid = $1 AND g.user_id = $2 `; const result = await pool.query(query, [generationUuid, userId]); return result.rows[0] || null; } /** * Получить метаданные generation по UUID с проверкой принадлежности пользователю */ export async function getGenerationMetaByUuid(generationUuid, userId) { const query = ` SELECT g.scenario_id, s.name as scenario_name FROM uno_bff.generations g LEFT JOIN uno_bff.scenarios s ON g.scenario_id = s.scenario_id WHERE g.generation_uuid = $1 AND g.user_id = $2 `; const result = await pool.query(query, [generationUuid, userId]); return result.rows[0] || null; } /** * Обновить generation result_payload и статус */ export async function updateGenerationResult(generationUuid, resultPayload, status = 'completed') { const query = ` UPDATE uno_bff.generations SET result_payload = $2, status = $3, finished_at = COALESCE(finished_at, now()), updated_at = now() WHERE generation_uuid = $1 RETURNING generation_uuid, user_id, scenario_id, status, result_payload `; const result = await pool.query(query, [generationUuid, JSON.stringify(resultPayload), status]); return result.rows[0] || null; } /** * Получить все шаги для generation */ export async function getGenerationSteps(generationUuid) { const query = ` SELECT step_id, step_order, status, request_payload, response_payload, error_payload, started_at, finished_at FROM uno_bff.generation_steps WHERE generation_uuid = $1 ORDER BY step_order ASC `; const result = await pool.query(query, [generationUuid]); return result.rows; }