{
  "openapi": "3.1.0",
  "info": {
    "title": "CellHood ELISA Analysis API",
    "version": "1.0.0",
    "description": "Server-side ELISA curve fitting, sample quantification, and branded report generation. Workbook parsing and layout review occur in the browser before structured data is submitted."
  },
  "servers": [{ "url": "/" }],
  "paths": {
    "/api/elisa/analyse": {
      "post": {
        "operationId": "analyseElisaPlate",
        "summary": "Fit an ELISA standard curve and quantify sample wells",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyseRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Completed analysis",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyseResponse" } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "405": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/elisa/export/excel": {
      "post": {
        "operationId": "exportElisaExcel",
        "summary": "Create a branded Excel report for a completed analysis",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportRequest" } } }
        },
        "responses": {
          "200": { "description": "Excel workbook", "content": { "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { "schema": { "type": "string", "contentEncoding": "binary" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/elisa/export/pdf": {
      "post": {
        "operationId": "exportElisaPdf",
        "summary": "Create a branded PDF report for a completed analysis",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReportRequest" } } }
        },
        "responses": {
          "200": { "description": "PDF report", "content": { "application/pdf": { "schema": { "type": "string", "contentEncoding": "binary" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "WellBase": {
        "type": "object",
        "required": ["well", "signal"],
        "properties": {
          "well": { "type": "string", "description": "Plate coordinate such as A01" },
          "row": { "type": "string" },
          "column": { "type": "integer" },
          "signal": { "type": "number" }
        },
        "additionalProperties": true
      },
      "StandardWell": {
        "allOf": [
          { "$ref": "#/components/schemas/WellBase" },
          {
            "type": "object",
            "required": ["standardConcentration"],
            "properties": { "standardConcentration": { "type": "number" } }
          }
        ]
      },
      "SampleWell": {
        "allOf": [
          { "$ref": "#/components/schemas/WellBase" },
          {
            "type": "object",
            "required": ["label"],
            "properties": {
              "label": { "type": "string" },
              "sample": { "type": "string" },
              "dilution": { "type": "number", "minimum": 1, "default": 1 }
            }
          }
        ]
      },
      "Normalisation": {
        "type": "object",
        "required": ["volumeUl", "cellsPerWell", "durationHours"],
        "properties": {
          "volumeUl": { "type": "number", "exclusiveMinimum": 0 },
          "cellsPerWell": { "type": "number", "exclusiveMinimum": 0 },
          "durationHours": { "type": "number", "exclusiveMinimum": 0 }
        },
        "additionalProperties": false
      },
      "AnalyseRequest": {
        "type": "object",
        "required": ["model", "standardWells", "sampleWells"],
        "properties": {
          "model": { "type": "string", "enum": ["4PL", "5PL"] },
          "standardWells": { "type": "array", "minItems": 1, "maxItems": 1536, "items": { "$ref": "#/components/schemas/StandardWell" } },
          "sampleWells": { "type": "array", "minItems": 1, "maxItems": 1536, "items": { "$ref": "#/components/schemas/SampleWell" } },
          "normalization": { "oneOf": [{ "$ref": "#/components/schemas/Normalisation" }, { "type": "null" }] }
        },
        "additionalProperties": false
      },
      "AnalyseResponse": {
        "type": "object",
        "required": ["fit", "results", "curvePoints"],
        "properties": {
          "fit": { "type": "object", "additionalProperties": true },
          "results": { "type": "object", "additionalProperties": true },
          "curvePoints": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["concentration", "signal"],
              "properties": { "concentration": { "type": "number" }, "signal": { "type": "number" } },
              "additionalProperties": false
            }
          }
        },
        "additionalProperties": false
      },
      "ReportRequest": {
        "type": "object",
        "required": ["state", "concentrationUnit"],
        "properties": {
          "state": {
            "type": "object",
            "required": ["file", "parsed", "fit", "results"],
            "properties": {
              "file": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" } }, "additionalProperties": false },
              "parsed": { "type": "object", "additionalProperties": true },
              "fit": { "type": "object", "additionalProperties": true },
              "results": { "type": "object", "additionalProperties": true },
              "applyDilution": { "type": "boolean" },
              "normalize": { "type": "boolean" },
              "normalization": { "type": "object", "additionalProperties": true }
            },
            "additionalProperties": true
          },
          "curveChartDataUrl": { "type": ["string", "null"], "description": "Optional PNG data URL of the rendered standard curve" },
          "concentrationUnit": { "type": "string", "minLength": 1, "maxLength": 40 }
        },
        "additionalProperties": false
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": { "error": { "type": "string" } },
        "additionalProperties": false
      }
    },
    "responses": {
      "Error": {
        "description": "Request error",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
