{ "openapi": "3.0.3", "info": { "title": "GCY HPC Server API", "description": "Slurm HPC cluster management API for job submission and cluster monitoring.", "version": "0.1.0" }, "servers": [ { "url": "/api/v1", "description": "API v1" } ], "tags": [ { "name": "Jobs", "description": "Job submission, listing, cancellation, and history" }, { "name": "Cluster", "description": "Cluster node, partition, and diagnostic information" }, { "name": "Applications", "description": "Application definition CRUD and job submission" }, { "name": "File Uploads", "description": "Chunked file upload with SHA256 dedup, breakpoint resume, and instant upload" }, { "name": "Files", "description": "File listing, metadata, download (with Range support), and deletion" }, { "name": "Folders", "description": "Folder CRUD with materialized path hierarchy" } ], "paths": { "/jobs/submit": { "post": { "tags": ["Jobs"], "summary": "Submit a new job", "description": "Submits a Slurm job with the specified script and optional parameters.", "operationId": "submitJob", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SubmitJobRequest" } } } }, "responses": { "201": { "description": "Job submitted successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/JobResponse" } } } ] } } } }, "400": { "description": "Invalid request body or missing required fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" }, "examples": { "invalid_body": { "value": { "success": false, "error": "invalid request body" } }, "missing_script": { "value": { "success": false, "error": "script is required" } } } } } }, "502": { "description": "Slurm backend error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/jobs": { "get": { "tags": ["Jobs"], "summary": "List all jobs with pagination", "description": "Retrieves a paginated list of all current jobs.", "operationId": "getJobs", "parameters": [ { "name": "page", "in": "query", "description": "Page number (starts from 1)", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1 } }, { "name": "page_size", "in": "query", "description": "Number of items per page", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 20 } } ], "responses": { "200": { "description": "Paginated list of jobs", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/JobListResponse" } } } ] } } } }, "400": { "description": "Invalid query parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/jobs/history": { "get": { "tags": ["Jobs"], "summary": "Get job history", "description": "Retrieves paginated job history with optional filters.", "operationId": "getJobHistory", "parameters": [ { "name": "users", "in": "query", "description": "Filter by username(s)", "schema": { "type": "string" } }, { "name": "start_time", "in": "query", "description": "Filter by start time (Unix timestamp or date string)", "schema": { "type": "string" } }, { "name": "end_time", "in": "query", "description": "Filter by end time (Unix timestamp or date string)", "schema": { "type": "string" } }, { "name": "account", "in": "query", "description": "Filter by account", "schema": { "type": "string" } }, { "name": "partition", "in": "query", "description": "Filter by partition", "schema": { "type": "string" } }, { "name": "state", "in": "query", "description": "Filter by job state", "schema": { "type": "string" } }, { "name": "job_name", "in": "query", "description": "Filter by job name", "schema": { "type": "string" } }, { "name": "submit_time", "in": "query", "description": "Filter by submit time (Unix timestamp)", "schema": { "type": "string" } }, { "name": "cluster", "in": "query", "description": "Filter by cluster name", "schema": { "type": "string" } }, { "name": "qos", "in": "query", "description": "Filter by QOS policy", "schema": { "type": "string" } }, { "name": "constraints", "in": "query", "description": "Filter by node constraints", "schema": { "type": "string" } }, { "name": "exit_code", "in": "query", "description": "Filter by exit code", "schema": { "type": "string" } }, { "name": "node", "in": "query", "description": "Filter by allocated node", "schema": { "type": "string" } }, { "name": "reservation", "in": "query", "description": "Filter by reservation name", "schema": { "type": "string" } }, { "name": "groups", "in": "query", "description": "Filter by user groups", "schema": { "type": "string" } }, { "name": "wckey", "in": "query", "description": "Filter by WCKey (Workload Characterization Key)", "schema": { "type": "string" } }, { "name": "page", "in": "query", "description": "Page number (default: 1)", "schema": { "type": "integer", "minimum": 1, "default": 1 } }, { "name": "page_size", "in": "query", "description": "Items per page (default: 20)", "schema": { "type": "integer", "minimum": 1, "default": 20 } } ], "responses": { "200": { "description": "Paginated job history", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/JobListResponse" } } } ] } } } }, "400": { "description": "Invalid query parameters", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/jobs/{id}": { "get": { "tags": ["Jobs"], "summary": "Get job by ID", "description": "Retrieves details for a specific job. If the job is not found in the active queue, automatically queries SlurmDBD history.", "operationId": "getJob", "parameters": [ { "$ref": "#/components/parameters/JobId" } ], "responses": { "200": { "description": "Job details", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/JobResponse" } } } ] } } } }, "404": { "description": "Job not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "delete": { "tags": ["Jobs"], "summary": "Cancel a job", "description": "Cancels a running or pending job by ID.", "operationId": "cancelJob", "parameters": [ { "$ref": "#/components/parameters/JobId" } ], "responses": { "200": { "description": "Job cancelled successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "message": { "type": "string", "example": "job cancelled" } } } } } ] } } } }, "502": { "description": "Slurm backend error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/nodes": { "get": { "tags": ["Cluster"], "summary": "List all nodes", "description": "Retrieves a list of all cluster nodes.", "operationId": "getNodes", "responses": { "200": { "description": "List of nodes", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/NodeResponse" } } } } ] } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/nodes/{name}": { "get": { "tags": ["Cluster"], "summary": "Get node by name", "description": "Retrieves details for a specific cluster node.", "operationId": "getNode", "parameters": [ { "$ref": "#/components/parameters/NodeName" } ], "responses": { "200": { "description": "Node details", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/NodeResponse" } } } ] } } } }, "404": { "description": "Node not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/partitions": { "get": { "tags": ["Cluster"], "summary": "List all partitions", "description": "Retrieves a list of all cluster partitions.", "operationId": "getPartitions", "responses": { "200": { "description": "List of partitions", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PartitionResponse" } } } } ] } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/partitions/{name}": { "get": { "tags": ["Cluster"], "summary": "Get partition by name", "description": "Retrieves details for a specific cluster partition.", "operationId": "getPartition", "parameters": [ { "$ref": "#/components/parameters/PartitionName" } ], "responses": { "200": { "description": "Partition details", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/PartitionResponse" } } } ] } } } }, "404": { "description": "Partition not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/applications": { "get": { "tags": ["Applications"], "summary": "List applications", "description": "Retrieves a paginated list of application definitions.", "operationId": "listApplications", "parameters": [ { "name": "page", "in": "query", "description": "Page number (starts from 1)", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 1 } }, { "name": "page_size", "in": "query", "description": "Number of items per page", "required": false, "schema": { "type": "integer", "minimum": 1, "default": 20 } } ], "responses": { "200": { "description": "Paginated list of applications", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/ApplicationListResponse" } } } ] } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "post": { "tags": ["Applications"], "summary": "Create an application", "description": "Creates a new application definition.", "operationId": "createApplication", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateApplicationRequest" } } } }, "responses": { "201": { "description": "Application created successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", "description": "Created application ID" } } } } } ] } } } }, "400": { "description": "Invalid request body or missing required fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/applications/{id}": { "get": { "tags": ["Applications"], "summary": "Get application by ID", "description": "Retrieves a specific application definition.", "operationId": "getApplication", "parameters": [ { "$ref": "#/components/parameters/ApplicationId" } ], "responses": { "200": { "description": "Application details", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Application" } } } ] } } } }, "404": { "description": "Application not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "put": { "tags": ["Applications"], "summary": "Update an application", "description": "Updates an existing application definition.", "operationId": "updateApplication", "parameters": [ { "$ref": "#/components/parameters/ApplicationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateApplicationRequest" } } } }, "responses": { "200": { "description": "Application updated successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "message": { "type": "string", "example": "application updated" } } } } } ] } } } }, "400": { "description": "Invalid request body", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "404": { "description": "Application not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "delete": { "tags": ["Applications"], "summary": "Delete an application", "description": "Deletes an application definition by ID.", "operationId": "deleteApplication", "parameters": [ { "$ref": "#/components/parameters/ApplicationId" } ], "responses": { "200": { "description": "Application deleted successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "object", "properties": { "message": { "type": "string", "example": "application deleted" } } } } } ] } } } }, "404": { "description": "Application not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/applications/{id}/submit": { "post": { "tags": ["Applications"], "summary": "Submit a job from an application", "description": "Submits a Slurm job using the application's script template and provided parameter values.", "operationId": "submitApplication", "parameters": [ { "$ref": "#/components/parameters/ApplicationId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApplicationSubmitRequest" } } } }, "responses": { "201": { "description": "Job submitted successfully", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/JobResponse" } } } ] } } } }, "400": { "description": "Invalid request body or missing required parameter values", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "404": { "description": "Application not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "502": { "description": "Slurm backend error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/diag": { "get": { "tags": ["Cluster"], "summary": "Get cluster diagnostics", "description": "Retrieves diagnostic information about the Slurm cluster.", "operationId": "getDiag", "responses": { "200": { "description": "Cluster diagnostics", "content": { "application/json": { "schema": { "allOf": [ { "$ref": "#/components/schemas/ApiResponseSuccess" }, { "type": "object", "properties": { "data": { "type": "object", "description": "Slurm cluster diagnostic data" } } } ] } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/uploads": { "post": { "tags": ["File Uploads"], "operationId": "initUpload", "summary": "Initialize a chunked upload session", "description": "Creates an upload session for chunked file upload. If a file with the same SHA256 already exists, returns the existing file immediately (instant upload / dedup).", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InitUploadRequest" } } } }, "responses": { "201": { "description": "Upload session created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadSessionResponse" } } } }, "200": { "description": "Dedup hit - file already exists, returns existing file", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileResponse" } } } }, "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/uploads/{sessionId}/chunks/{chunkIndex}": { "put": { "tags": ["File Uploads"], "operationId": "uploadChunk", "summary": "Upload a single chunk", "description": "Uploads a file chunk for the specified session. Chunks can be uploaded in any order and are idempotent.", "parameters": [ { "$ref": "#/components/parameters/SessionId" }, { "$ref": "#/components/parameters/ChunkIndex" } ], "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "required": ["chunk"], "properties": { "chunk": { "type": "string", "format": "binary", "description": "File chunk data" } } } } } }, "responses": { "200": { "description": "Chunk uploaded successfully" }, "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "404": { "description": "Upload session not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/uploads/{sessionId}/complete": { "post": { "tags": ["File Uploads"], "operationId": "completeUpload", "summary": "Complete an upload session", "description": "Finalizes the upload by merging all chunks via ComposeObject. Supports retry if previously failed.", "parameters": [ { "$ref": "#/components/parameters/SessionId" } ], "responses": { "201": { "description": "Upload completed, returns file", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileResponse" } } } }, "400": { "description": "Invalid request or missing chunks", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "404": { "description": "Upload session not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/uploads/{sessionId}": { "get": { "tags": ["File Uploads"], "operationId": "getUploadStatus", "summary": "Get upload session status", "description": "Returns the current status of an upload session including list of uploaded chunk indices.", "parameters": [ { "$ref": "#/components/parameters/SessionId" } ], "responses": { "200": { "description": "Upload session status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadSessionResponse" } } } }, "404": { "description": "Upload session not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "delete": { "tags": ["File Uploads"], "operationId": "cancelUpload", "summary": "Cancel an upload session", "description": "Cancels an in-progress upload, deletes uploaded chunks from MinIO, and removes the session.", "parameters": [ { "$ref": "#/components/parameters/SessionId" } ], "responses": { "200": { "description": "Upload cancelled successfully" }, "404": { "description": "Upload session not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files": { "get": { "tags": ["Files"], "operationId": "listFiles", "summary": "List files with pagination", "parameters": [ { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1 } }, { "name": "page_size", "in": "query", "schema": { "type": "integer", "default": 20 } }, { "name": "folder_id", "in": "query", "required": false, "description": "Filter by folder ID", "schema": { "type": "integer", "format": "int64" } }, { "name": "search", "in": "query", "required": false, "description": "Search files by name", "schema": { "type": "string" } } ], "responses": { "200": { "description": "List of files", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileListResponse" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/{id}": { "get": { "tags": ["Files"], "operationId": "getFile", "summary": "Get file metadata", "parameters": [ { "$ref": "#/components/parameters/FileId" } ], "responses": { "200": { "description": "File metadata", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FileResponse" } } } }, "404": { "description": "File not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "delete": { "tags": ["Files"], "operationId": "deleteFile", "summary": "Delete a file", "description": "Soft-deletes a file. If no other files reference the same blob, the blob is removed from MinIO.", "parameters": [ { "$ref": "#/components/parameters/FileId" } ], "responses": { "200": { "description": "File deleted successfully" }, "404": { "description": "File not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/{id}/download": { "get": { "tags": ["Files"], "operationId": "downloadFile", "summary": "Download a file", "description": "Downloads the file content. Supports HTTP Range header for partial content delivery.", "parameters": [ { "$ref": "#/components/parameters/FileId" }, { "name": "Range", "in": "header", "required": false, "description": "Byte range for partial content", "example": "bytes=0-1023", "schema": { "type": "string" } } ], "responses": { "200": { "description": "Full file content", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "206": { "description": "Partial content", "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } }, "404": { "description": "File not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/folders": { "post": { "tags": ["Folders"], "operationId": "createFolder", "summary": "Create a folder", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateFolderRequest" } } } }, "responses": { "201": { "description": "Folder created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FolderResponse" } } } }, "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "get": { "tags": ["Folders"], "operationId": "listFolders", "summary": "List folders", "parameters": [ { "name": "parent_id", "in": "query", "required": false, "description": "Parent folder ID (null for root)", "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "List of folders", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/FolderResponse" } } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } }, "/files/folders/{id}": { "get": { "tags": ["Folders"], "operationId": "getFolder", "summary": "Get folder details", "parameters": [ { "$ref": "#/components/parameters/FolderId" } ], "responses": { "200": { "description": "Folder details", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FolderResponse" } } } }, "404": { "description": "Folder not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } }, "delete": { "tags": ["Folders"], "operationId": "deleteFolder", "summary": "Delete a folder", "description": "Deletes an empty folder. Cannot delete folders that contain files or sub-folders.", "parameters": [ { "$ref": "#/components/parameters/FolderId" } ], "responses": { "200": { "description": "Folder deleted successfully" }, "400": { "description": "Folder is not empty", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "404": { "description": "Folder not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } }, "500": { "description": "Internal server error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiResponseError" } } } } } } } }, "components": { "parameters": { "JobId": { "name": "id", "in": "path", "required": true, "description": "Job ID", "schema": { "type": "string" } }, "NodeName": { "name": "name", "in": "path", "required": true, "description": "Node name", "schema": { "type": "string" } }, "PartitionName": { "name": "name", "in": "path", "required": true, "description": "Partition name", "schema": { "type": "string" } }, "ApplicationId": { "name": "id", "in": "path", "required": true, "description": "Application ID", "schema": { "type": "integer", "format": "int64" } }, "SessionId": { "name": "sessionId", "in": "path", "required": true, "description": "Upload session ID", "schema": { "type": "integer", "format": "int64" } }, "ChunkIndex": { "name": "chunkIndex", "in": "path", "required": true, "description": "Chunk index (0-based)", "schema": { "type": "integer", "minimum": 0 } }, "FileId": { "name": "id", "in": "path", "required": true, "description": "File ID", "schema": { "type": "integer", "format": "int64" } }, "FolderId": { "name": "id", "in": "path", "required": true, "description": "Folder ID", "schema": { "type": "integer", "format": "int64" } } }, "schemas": { "ApiResponseSuccess": { "type": "object", "required": ["success"], "properties": { "success": { "type": "boolean", "enum": [true] }, "data": { "description": "Response payload" } } }, "ApiResponseError": { "type": "object", "required": ["success", "error"], "properties": { "success": { "type": "boolean", "enum": [false] }, "error": { "type": "string", "description": "Error message" } } }, "SubmitJobRequest": { "type": "object", "required": ["script"], "properties": { "script": { "type": "string", "description": "Job script content" }, "partition": { "type": "string", "description": "Target partition" }, "qos": { "type": "string", "description": "Quality of Service" }, "cpus": { "type": "integer", "format": "int32", "description": "Number of CPUs required" }, "memory": { "type": "string", "description": "Memory requirement (e.g. \"4G\")" }, "time_limit": { "type": "string", "description": "Time limit (e.g. \"1:00:00\")" }, "job_name": { "type": "string", "description": "Job name" }, "environment": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Environment variables" } } }, "JobResponse": { "type": "object", "properties": { "job_id": { "type": "integer", "format": "int32", "description": "Slurm job ID" }, "name": { "type": "string", "description": "Job name" }, "job_state": { "type": "array", "items": { "type": "string" }, "description": "Current job state(s) (e.g. [\"RUNNING\"], [\"PENDING\",\"REQUEUED\"])" }, "state_reason": { "type": "string", "description": "Reason for job pending or failure" }, "partition": { "type": "string", "description": "Assigned partition" }, "qos": { "type": "string", "description": "Quality of Service policy" }, "priority": { "type": "integer", "format": "int32", "description": "Job priority", "nullable": true }, "time_limit": { "type": "string", "description": "Time limit in minutes (\"UNLIMITED\" for unlimited)" }, "account": { "type": "string", "description": "Billing account" }, "user": { "type": "string", "description": "Submitting user" }, "cluster": { "type": "string", "description": "Cluster name" }, "cpus": { "type": "integer", "format": "int32", "description": "Allocated/requested CPU cores", "nullable": true }, "tasks": { "type": "integer", "format": "int32", "description": "Number of tasks", "nullable": true }, "node_count": { "type": "integer", "format": "int32", "description": "Number of allocated nodes", "nullable": true }, "nodes": { "type": "string", "description": "Allocated node list" }, "batch_host": { "type": "string", "description": "Batch host node" }, "submit_time": { "type": "integer", "format": "int64", "description": "Submit time (Unix timestamp)", "nullable": true }, "start_time": { "type": "integer", "format": "int64", "description": "Start time (Unix timestamp)", "nullable": true }, "end_time": { "type": "integer", "format": "int64", "description": "End time (Unix timestamp)", "nullable": true }, "exit_code": { "type": "integer", "format": "int32", "description": "Exit code (null if not finished)", "nullable": true }, "standard_output": { "type": "string", "description": "Stdout file path" }, "standard_error": { "type": "string", "description": "Stderr file path" }, "standard_input": { "type": "string", "description": "Stdin file path" }, "working_directory": { "type": "string", "description": "Working directory" }, "command": { "type": "string", "description": "Executed command" }, "array_job_id": { "type": "integer", "format": "int32", "description": "Parent job ID for array jobs", "nullable": true }, "array_task_id": { "type": "integer", "format": "int32", "description": "Task ID within array job", "nullable": true } } }, "JobListResponse": { "type": "object", "properties": { "jobs": { "type": "array", "items": { "$ref": "#/components/schemas/JobResponse" }, "description": "List of jobs" }, "total": { "type": "integer", "description": "Total number of matching jobs" }, "page": { "type": "integer", "description": "Current page number (starts at 1)" }, "page_size": { "type": "integer", "description": "Items per page" } } }, "NodeResponse": { "type": "object", "properties": { "name": { "type": "string", "description": "Node hostname" }, "state": { "type": "array", "items": { "type": "string" }, "description": "Node state(s) (e.g. [\"IDLE\"], [\"ALLOCATED\",\"COMPLETING\"])" }, "reason": { "type": "string", "description": "Reason for DOWN/DRAIN state" }, "reason_set_by_user": { "type": "string", "description": "User who set the reason" }, "cpus": { "type": "integer", "format": "int32", "description": "Total CPU cores" }, "alloc_cpus": { "type": "integer", "format": "int32", "description": "Allocated CPU cores", "nullable": true }, "cores": { "type": "integer", "format": "int32", "description": "Physical cores", "nullable": true }, "sockets": { "type": "integer", "format": "int32", "description": "CPU sockets", "nullable": true }, "threads": { "type": "integer", "format": "int32", "description": "Threads per core", "nullable": true }, "cpu_load": { "type": "integer", "format": "int32", "description": "CPU load (kernel nice value * 100)", "nullable": true }, "real_memory": { "type": "integer", "format": "int64", "description": "Total physical memory (MiB)" }, "alloc_memory": { "type": "integer", "format": "int64", "description": "Allocated memory (MiB)" }, "free_mem": { "type": "integer", "format": "int64", "description": "Free memory (MiB)", "nullable": true }, "architecture": { "type": "string", "description": "System architecture (e.g. x86_64)" }, "operating_system": { "type": "string", "description": "Operating system version" }, "gres": { "type": "string", "description": "Available generic resources (e.g. \"gpu:4\")" }, "gres_used": { "type": "string", "description": "Used generic resources (e.g. \"gpu:2\")" }, "address": { "type": "string", "description": "Node address (IP)" }, "hostname": { "type": "string", "description": "Node hostname (may differ from name)" }, "weight": { "type": "integer", "format": "int32", "description": "Scheduling weight", "nullable": true }, "features": { "type": "string", "description": "Node feature tags (modifiable)" }, "active_features": { "type": "string", "description": "Active feature tags (read-only)" } } }, "PartitionResponse": { "type": "object", "properties": { "name": { "type": "string", "description": "Partition name" }, "state": { "type": "array", "items": { "type": "string" }, "description": "Partition state(s) (e.g. [\"UP\"], [\"DOWN\",\"DRAIN\"])" }, "default": { "type": "boolean", "description": "Whether this is the default partition" }, "nodes": { "type": "string", "description": "Node range string" }, "total_nodes": { "type": "integer", "format": "int32", "description": "Total nodes in partition" }, "total_cpus": { "type": "integer", "format": "int32", "description": "Total CPUs in partition" }, "max_cpus_per_node": { "type": "integer", "format": "int32", "description": "Max CPUs per node", "nullable": true }, "max_time": { "type": "string", "description": "Maximum time limit (\"UNLIMITED\" for unlimited)" }, "max_nodes": { "type": "integer", "format": "int32", "description": "Max nodes per job", "nullable": true }, "min_nodes": { "type": "integer", "format": "int32", "description": "Min nodes per job", "nullable": true }, "default_time": { "type": "string", "description": "Default time limit" }, "grace_time": { "type": "integer", "format": "int32", "description": "Grace time after preemption (seconds)", "nullable": true }, "priority": { "type": "integer", "format": "int32", "description": "Job priority factor within partition", "nullable": true }, "qos_allowed": { "type": "string", "description": "Allowed QOS list" }, "qos_deny": { "type": "string", "description": "Denied QOS list" }, "qos_assigned": { "type": "string", "description": "Default assigned QOS" }, "accounts_allowed": { "type": "string", "description": "Allowed accounts list" }, "accounts_deny": { "type": "string", "description": "Denied accounts list" } } }, "ParameterSchema": { "type": "object", "required": ["name", "type"], "properties": { "name": { "type": "string", "description": "Parameter name" }, "label": { "type": "string", "description": "Display label" }, "type": { "type": "string", "enum": ["string", "integer", "enum", "file", "directory", "boolean"], "description": "Parameter type" }, "required": { "type": "boolean", "description": "Whether this parameter is required" }, "default": { "type": "string", "description": "Default value" }, "options": { "type": "array", "items": { "type": "string" }, "description": "Available options for enum type" }, "description": { "type": "string", "description": "Parameter description" } } }, "Application": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", "description": "Application ID" }, "name": { "type": "string", "description": "Application name" }, "description": { "type": "string", "description": "Application description" }, "icon": { "type": "string", "description": "Application icon" }, "category": { "type": "string", "description": "Application category" }, "script_template": { "type": "string", "description": "Job script template" }, "parameters": { "type": "array", "items": { "$ref": "#/components/schemas/ParameterSchema" }, "description": "Parameter definitions" }, "scope": { "type": "string", "description": "Application scope", "default": "system" }, "created_by": { "type": "integer", "format": "int64", "description": "Creator user ID", "nullable": true }, "created_at": { "type": "string", "format": "date-time", "description": "Creation timestamp", "nullable": true }, "updated_at": { "type": "string", "format": "date-time", "description": "Last update timestamp", "nullable": true } } }, "CreateApplicationRequest": { "type": "object", "required": ["name", "script_template"], "properties": { "name": { "type": "string", "description": "Application name" }, "description": { "type": "string", "description": "Application description" }, "icon": { "type": "string", "description": "Application icon" }, "category": { "type": "string", "description": "Application category" }, "script_template": { "type": "string", "description": "Job script template" }, "parameters": { "type": "array", "items": { "$ref": "#/components/schemas/ParameterSchema" }, "description": "Parameter definitions" }, "scope": { "type": "string", "description": "Application scope", "default": "system" } } }, "UpdateApplicationRequest": { "type": "object", "properties": { "name": { "type": "string", "description": "Application name" }, "description": { "type": "string", "description": "Application description" }, "icon": { "type": "string", "description": "Application icon" }, "category": { "type": "string", "description": "Application category" }, "script_template": { "type": "string", "description": "Job script template" }, "parameters": { "type": "array", "items": { "$ref": "#/components/schemas/ParameterSchema" }, "description": "Parameter definitions" }, "scope": { "type": "string", "description": "Application scope" } } }, "ApplicationSubmitRequest": { "type": "object", "required": ["values"], "properties": { "values": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Parameter name to value mapping" } } }, "ApplicationListResponse": { "type": "object", "properties": { "applications": { "type": "array", "items": { "$ref": "#/components/schemas/Application" }, "description": "List of applications" }, "total": { "type": "integer", "description": "Total number of applications" }, "page": { "type": "integer", "description": "Current page number" }, "page_size": { "type": "integer", "description": "Items per page" } } }, "InitUploadRequest": { "type": "object", "required": ["file_name", "file_size", "sha256", "chunk_size"], "properties": { "file_name": { "type": "string", "description": "File name" }, "file_size": { "type": "integer", "format": "int64", "description": "Total file size in bytes" }, "sha256": { "type": "string", "description": "SHA256 hash of the entire file (hex encoded)" }, "chunk_size": { "type": "integer", "format": "int64", "description": "Chunk size in bytes (must be >= min_chunk_size config)" }, "folder_id": { "type": "integer", "format": "int64", "description": "Target folder ID (null for root)", "nullable": true } } }, "UploadSessionResponse": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", "description": "Session ID" }, "file_name": { "type": "string", "description": "File name" }, "file_size": { "type": "integer", "format": "int64", "description": "Total file size in bytes" }, "chunk_size": { "type": "integer", "format": "int64", "description": "Chunk size in bytes" }, "total_chunks": { "type": "integer", "description": "Total number of chunks" }, "sha256": { "type": "string", "description": "SHA256 hash of the entire file" }, "status": { "type": "string", "enum": ["pending", "uploading", "merging", "completed", "failed", "cancelled", "expired"], "description": "Session status" }, "uploaded_chunks": { "type": "array", "items": { "type": "integer" }, "description": "List of uploaded chunk indices" }, "expires_at": { "type": "string", "format": "date-time", "description": "Session expiration time" } } }, "FileResponse": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", "description": "File ID" }, "name": { "type": "string", "description": "File name" }, "folder_id": { "type": "integer", "format": "int64", "description": "Parent folder ID", "nullable": true }, "size": { "type": "integer", "format": "int64", "description": "File size in bytes" }, "mime_type": { "type": "string", "description": "MIME type" }, "sha256": { "type": "string", "description": "SHA256 hash" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "FileListResponse": { "type": "object", "properties": { "files": { "type": "array", "items": { "$ref": "#/components/schemas/FileResponse" }, "description": "List of files" }, "total": { "type": "integer", "description": "Total number of matching files" }, "page": { "type": "integer", "description": "Current page number" }, "page_size": { "type": "integer", "description": "Items per page" } } }, "FolderResponse": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64", "description": "Folder ID" }, "name": { "type": "string", "description": "Folder name" }, "parent_id": { "type": "integer", "format": "int64", "description": "Parent folder ID (null for root)", "nullable": true }, "path": { "type": "string", "description": "Materialized path (e.g. /data/reports/)" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "CreateFolderRequest": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string", "description": "Folder name (no path traversal characters)" }, "parent_id": { "type": "integer", "format": "int64", "description": "Parent folder ID (null for root)", "nullable": true } } } } } }