$success]; if ($success) { $response['data'] = $dataOrError; } else { $response['error'] = $dataOrError; } echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); exit; } try { // Only POST allowed if ($_SERVER['REQUEST_METHOD'] !== 'POST') { sendResponse(false, ['code' => 'METHOD_NOT_ALLOWED', 'message' => 'Only POST requests are allowed.'], 405); } // Read JSON input or FormData $input = file_get_contents('php://input'); $data = json_decode($input, true); // If multipart/form-data, action and project_id are in $_POST if (!$data && !empty($_POST)) { $data = [ 'action' => $_POST['action'] ?? null, 'project_id' => $_POST['project_id'] ?? null, 'payload' => $_POST['payload'] ?? [] ]; if (is_string($data['payload'])) { $data['payload'] = json_decode($data['payload'], true); } } if (!$data && $_SERVER['REQUEST_METHOD'] === 'POST') { sendResponse(false, ['code' => 'INVALID_JSON', 'message' => 'Invalid JSON input.'], 400); } // Validate action $action = $data['action'] ?? null; if (!$action) { sendResponse(false, ['code' => 'MISSING_ACTION', 'message' => 'Action is required.'], 400); } // Check X-User-ID header (except for initSession) $userId = $_SERVER['HTTP_X_USER_ID'] ?? $_POST['X-User-ID'] ?? null; if (!$userId && $action !== 'initSession') { sendResponse(false, ['code' => 'UNAUTHORIZED', 'message' => 'X-User-ID is missing.'], 401); } // Router $projectActions = new \App\Actions\ProjectActions(); $taskActions = new \App\Actions\TaskActions(); $consentService = new \App\Services\ConsentService(); switch ($action) { case 'ping': sendResponse(true, ['message' => 'pong', 'timestamp' => time()]); break; case 'initSession': sendResponse(true, $projectActions->initSession()); break; case 'getCategories': $storage = new \App\Services\FileStorage(); sendResponse(true, $storage->get('categories.json')); break; case 'createProject': sendResponse(true, $projectActions->createProject($userId)); break; case 'listProjects': sendResponse(true, $projectActions->listProjects($userId)); break; case 'getProjectStatus': $projectId = $data['project_id'] ?? null; if (!$projectId) { sendResponse(false, ['code' => 'MISSING_PROJECT_ID', 'message' => 'Project ID is required.'], 400); } sendResponse(true, $projectActions->getProjectStatus($userId, $projectId)); break; case 'saveStep': $projectId = $data['project_id'] ?? null; $step = (int)($data['payload']['step'] ?? 0); $payloadData = $data['payload']['data'] ?? null; if (!$projectId || !$step || !$payloadData) { sendResponse(false, ['code' => 'MISSING_DATA', 'message' => 'Project ID, step and data are required.'], 400); } $success = $projectActions->saveStep($userId, $projectId, $step, $payloadData); sendResponse($success, ['message' => 'Step saved successfully.']); break; case 'saveConsent': $projectId = $data['project_id'] ?? null; $consentText = $data['payload']['consent_text'] ?? null; if (!$projectId || !$consentText) { sendResponse(false, ['code' => 'MISSING_DATA', 'message' => 'Project ID and consent text are required.'], 400); } $success = $consentService->saveConsent($projectId, $userId, $consentText); sendResponse($success, ['message' => 'Consent saved successfully.']); break; case 'uploadAsset': $projectId = $data['project_id'] ?? null; if (!$projectId || empty($_FILES['file'])) { sendResponse(false, ['code' => 'MISSING_DATA', 'message' => 'Project ID and file are required.'], 400); } $result = $projectActions->uploadAsset($userId, $projectId, $_FILES['file']); sendResponse(true, $result); break; case 'generateWebsite': $projectId = $data['project_id'] ?? null; if (!$projectId) { sendResponse(false, ['code' => 'MISSING_PROJECT_ID', 'message' => 'Project ID is required.'], 400); } sendResponse(true, $taskActions->generateWebsite($userId, $projectId)); break; default: sendResponse(false, ['code' => 'UNKNOWN_ACTION', 'message' => "Action '$action' is not defined."], 404); break; } } catch (Throwable $e) { sendResponse(false, [ 'code' => 'INTERNAL_SERVER_ERROR', 'message' => $e->getMessage() ], 500); }