{
  "openapi": "3.0.3",
  "info": {
    "title": "mitch-risk API",
    "version": "1.0.0",
    "description": "REST API for mitch-risk — a lightweight third party vendor risk management solution. Supports two authentication methods: browser session cookies (log in via the web app) and API keys (generated in Settings → API). API keys use Bearer token authentication and must be enabled by an admin before they can be used. API keys grant full access to every endpoint and remain valid independently of the account that created them. Keys can be IP-restricted and have configurable expiry.",
    "contact": {
      "name": "mitch-risk",
      "url": "https://github.com/mitchelljfranklin/mitch-risk"
    }
  },
  "servers": [
    {
      "url": "/api",
      "description": "Vendor risk management API (v1)"
    }
  ],
  "security": [
    {
      "sessionCookie": []
    },
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Vendors",
      "description": "Vendor management — list, search, view, export, import, update, and delete vendors. Certifications for each vendor."
    },
    {
      "name": "Assessments",
      "description": "Assessment management — list, detail, CSV export, and PDF reports"
    },
    {
      "name": "Templates",
      "description": "Template management — export questionnaire templates as JSON"
    },
    {
      "name": "Findings",
      "description": "Findings management — list open findings and update their status (Remediated / Risk Accepted)"
    },
    {
      "name": "Frameworks",
      "description": "Compliance frameworks — list frameworks and view framework detail with controls"
    },
    {
      "name": "Dashboard",
      "description": "Dashboard metrics — aggregated portfolio overview for dashboards and BI tools"
    },
    {
      "name": "Audit",
      "description": "Audit log — query activity trail for SIEM integration and compliance"
    }
  ],
  "paths": {
    "/v1/vendors": {
      "get": {
        "tags": ["Vendors"],
        "summary": "List and search vendors",
        "description": "Returns all vendors, optionally filtered by name/email search query or tier. Unauthenticated requests receive 401.",
        "operationId": "listVendors",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "description": "Case-insensitive search across vendor name and contact email",
            "schema": {
              "type": "string"
            },
            "example": "acme"
          },
          {
            "name": "tier",
            "in": "query",
            "description": "Filter by vendor risk tier",
            "schema": {
              "type": "string",
              "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "description": "Filter vendors by tag",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "externalId",
            "in": "query",
            "required": false,
            "description": "Filter by exact external ID reference",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of vendors matching the criteria",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/VendorSummary"
                  }
                },
                "example": [
                  {
                    "id": "cmr182ra30001iuo4z6iqcdfs",
                    "name": "Acme Corp",
                    "externalId": "ERP-V-001",
                    "contactName": "Jane Doe",
                    "contactEmail": "jane@acme.example",
                    "tier": "HIGH",
                    "website": "https://acme.example",
                    "overallScore": 0.72,
                    "lastAssessedAt": "2026-06-15T10:00:00.000Z",
                    "assessmentCount": 3
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/vendors/{vendorId}": {
      "get": {
        "tags": ["Vendors"],
        "summary": "Get vendor detail",
        "description": "Returns full vendor profile including contact info, scores, assessment history, and domain compliance breakdown.",
        "operationId": "getVendor",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "description": "The vendor's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full vendor detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "tags": ["Vendors"],
        "summary": "Update vendor",
        "description": "Updates a vendor's details. All fields are optional — fields omitted from the request body retain their existing values. Returns 409 if the provided externalId is already assigned to a different vendor.",
        "operationId": "updateVendor",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "description": "The vendor's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VendorUpdate"
              },
              "example": {
                "name": "Acme Corp (Updated)",
                "tier": "HIGH",
                "contactName": "Jane Smith"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vendor updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorUpdated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Conflict — another vendor already uses this externalId",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "error": "A vendor with this external ID already exists."
                  }
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": ["Vendors"],
        "summary": "Delete vendor",
        "description": "Permanently deletes a vendor and all associated assessments, responses, evidence, and findings. This action is irreversible.",
        "operationId": "deleteVendor",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "description": "The vendor's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Vendor deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletedResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/external/{externalId}": {
      "get": {
        "tags": ["Vendors"],
        "summary": "Get vendor by external ID",
        "description": "Returns full vendor detail looked up by its external ID reference (the vendor's ID in another system). Returns 404 if no vendor carries that external ID.",
        "operationId": "getVendorByExternalId",
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "description": "The vendor's external ID reference",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full vendor detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/{vendorId}/score": {
      "get": {
        "tags": ["Vendors"],
        "summary": "Get vendor score summary",
        "description": "Returns a lightweight score summary for a vendor — useful for dashboards and integrations.",
        "operationId": "getVendorScore",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Vendor score summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorScore"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/{vendorId}/export": {
      "get": {
        "tags": ["Vendors"],
        "summary": "Export vendor as CSV",
        "description": "Downloads a CSV file containing vendor details, assessment summaries, certifications, and customer responsibility actions. Suitable for spreadsheet import or backup.",
        "operationId": "exportVendor",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV download of vendor data",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "attachment; filename=\"{name}.csv\""
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/import": {
      "post": {
        "tags": ["Vendors"],
        "summary": "Import vendor from JSON",
        "description": "Create a new vendor from a JSON body. The body must contain at minimum `name` and `contactEmail`.",
        "operationId": "importVendor",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VendorImport"
              },
              "example": {
                "name": "NewCo Ltd",
                "contactName": "John Smith",
                "contactEmail": "john@newco.example",
                "tier": "MEDIUM",
                "website": "https://newco.example",
                "notes": "Key supplier for cloud infrastructure"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Vendor created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorCreated"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input — missing fields or bad data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Vendor name is required"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/audit": {
      "get": {
        "tags": ["Audit"],
        "summary": "Query audit log",
        "description": "Returns audit trail entries with optional filters for activity type, user, date range, and pagination. Supports both JSON and CSV output. Rate-limited to 60/min per API key. 10 results per page.",
        "operationId": "listAuditLogs",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "description": "Filter by audit action type (e.g. LOGIN, CREATE_VENDOR, PUBLISH_TEMPLATE)",
            "schema": {
              "type": "string"
            },
            "example": "LOGIN"
          },
          {
            "name": "userId",
            "in": "query",
            "description": "Filter by user ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "description": "Start of date range (ISO 8601 date)",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-06-01"
          },
          {
            "name": "toDate",
            "in": "query",
            "description": "End of date range (ISO 8601 date)",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-07-01"
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number for pagination (default 1)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Response format — JSON array or CSV download",
            "schema": {
              "type": "string",
              "enum": ["json", "csv"],
              "default": "json"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "description": "Number of results per page (default 10)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit entries with pagination (JSON)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditEntry"
                      }
                    },
                    "page": {
                      "type": "integer"
                    },
                    "pageSize": {
                      "type": "integer"
                    },
                    "totalCount": {
                      "type": "integer"
                    }
                  }
                },
                "example": [
                  {
                    "id": "abc123",
                    "action": "LOGIN",
                    "actionLabel": "Login",
                    "userName": "Admin User",
                    "entityType": null,
                    "entityId": null,
                    "createdAt": "2026-07-01T12:00:00.000Z"
                  },
                  {
                    "id": "def456",
                    "action": "CREATE_VENDOR",
                    "actionLabel": "Created vendor",
                    "userName": "Jane Reviewer",
                    "entityType": "Vendor",
                    "entityId": "cmr182ra3",
                    "createdAt": "2026-07-01T11:30:00.000Z"
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/assessments/{assessmentId}/export": {
      "get": {
        "tags": ["Assessments"],
        "summary": "Export assessment as CSV",
        "description": "Downloads a CSV file containing all responses (with compliance status) and findings for an assessment.",
        "operationId": "exportAssessmentCsv",
        "parameters": [
          {
            "name": "assessmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "CSV download",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "attachment; filename=\"{vendor}-assessment.csv\""
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/assessments/{assessmentId}/pdf": {
      "get": {
        "tags": ["Assessments"],
        "summary": "Export assessment as PDF",
        "description": "Generates and downloads a PDF report containing the assessment responses, score, findings, and vendor details. Branded with the organisation name.",
        "operationId": "exportAssessmentPdf",
        "parameters": [
          {
            "name": "assessmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF download",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/templates/{templateId}/export": {
      "get": {
        "tags": ["Templates"],
        "summary": "Export template as JSON",
        "description": "Downloads a JSON file containing the template structure — sections, questions, types, weights, options, expected answers, conditional logic, and control mappings. Can be re-imported via the UI import form.",
        "operationId": "exportTemplate",
        "parameters": [
          {
            "name": "templateId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON download of the template",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateExport"
                }
              }
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "attachment; filename=\"{name}.json\""
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/assessments": {
      "get": {
        "tags": ["Assessments"],
        "summary": "List assessments",
        "description": "Returns paginated assessment list with optional filters: vendorId, status, fromDate, toDate, query. Supports JSON and CSV output.",
        "operationId": "listAssessments",
        "parameters": [
          {
            "name": "vendorId",
            "in": "query",
            "description": "Filter by vendor ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by assessment status",
            "schema": {
              "type": "string",
              "enum": [
                "DRAFT",
                "SENT",
                "IN_PROGRESS",
                "SUBMITTED",
                "UNDER_REVIEW",
                "COMPLETED"
              ]
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "description": "Start of date range (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "description": "End of date range (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number (default 1)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": false,
            "description": "Search term to filter assessments by title",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "overdue",
            "in": "query",
            "required": false,
            "description": "Set to 'true' to show only overdue assessments",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Response format",
            "schema": {
              "type": "string",
              "enum": ["json", "csv"],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of assessments (JSON) or CSV download",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssessmentList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/assessments/{assessmentId}": {
      "get": {
        "tags": ["Assessments"],
        "summary": "Get assessment detail",
        "description": "Returns full assessment detail: vendor info, template, questions with responses, review decisions, findings, and threaded comments.",
        "operationId": "getAssessment",
        "parameters": [
          {
            "name": "assessmentId",
            "in": "path",
            "required": true,
            "description": "The assessment's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full assessment detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssessmentDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/{vendorId}/assessments": {
      "get": {
        "tags": ["Vendors"],
        "summary": "List vendor assessments",
        "description": "Returns all assessments for a specific vendor. Convenience shortcut for /v1/assessments?vendorId=X.",
        "operationId": "listVendorAssessments",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "description": "The vendor's unique ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number (default 1)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by assessment status",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of vendor assessments",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendorAssessmentList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/vendors/{vendorId}/certifications": {
      "get": {
        "tags": ["Vendors"],
        "summary": "List vendor certifications",
        "description": "Returns all certifications for a vendor with attachment details.",
        "operationId": "listVendorCertifications",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "description": "The vendor's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of vendor certifications",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CertificationList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/findings": {
      "get": {
        "tags": ["Findings"],
        "summary": "List findings",
        "description": "Returns paginated findings across all vendors. Filter by status, severity, or vendorId.",
        "operationId": "listFindings",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Filter by finding status",
            "schema": {
              "type": "string",
              "enum": ["OPEN", "REMEDIATED", "RISK_ACCEPTED"]
            }
          },
          {
            "name": "severity",
            "in": "query",
            "description": "Filter by severity",
            "schema": {
              "type": "string",
              "enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
            }
          },
          {
            "name": "vendorId",
            "in": "query",
            "description": "Filter by vendor ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Page number (default 1)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated findings list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindingList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/findings/{findingId}": {
      "patch": {
        "tags": ["Findings"],
        "summary": "Update finding status",
        "description": "Transition a finding from OPEN to REMEDIATED or RISK_ACCEPTED. Cannot transition from already-closed states.",
        "operationId": "updateFindingStatus",
        "parameters": [
          {
            "name": "findingId",
            "in": "path",
            "required": true,
            "description": "The finding's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindingStatusUpdate"
              },
              "example": {
                "status": "REMEDIATED",
                "resolutionNote": "Vendor has implemented the required control."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Finding status updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FindingUpdated"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/frameworks": {
      "get": {
        "tags": ["Frameworks"],
        "summary": "List frameworks",
        "description": "Returns all compliance frameworks with control counts.",
        "operationId": "listFrameworks",
        "responses": {
          "200": {
            "description": "List of frameworks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FrameworkSummary"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/frameworks/{frameworkId}": {
      "get": {
        "tags": ["Frameworks"],
        "summary": "Get framework detail",
        "description": "Returns a framework with all its controls. Supports optional search query to filter controls by code, title, domain, or guidance.",
        "operationId": "getFramework",
        "parameters": [
          {
            "name": "frameworkId",
            "in": "path",
            "required": true,
            "description": "The framework's unique ID",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search controls by text (code, title, domain, guidance)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Framework detail with controls",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FrameworkDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": ["Frameworks"],
        "summary": "Delete a framework",
        "description": "Permanently deletes a framework and all its controls. Template questions mapped to these controls lose their assignments. Existing assessments and findings are unaffected. Requires frameworks:delete permission.",
        "operationId": "deleteFramework",
        "parameters": [
          {
            "name": "frameworkId",
            "in": "path",
            "required": true,
            "description": "The framework's unique ID",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Framework deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dashboard": {
      "get": {
        "tags": ["Dashboard"],
        "summary": "Get dashboard summary",
        "description": "Returns aggregated portfolio metrics: vendor counts, average score, RAG score distribution, vendor-by-tier counts, top 10 deficient controls, open findings count, and assessment status breakdown. No per-vendor PII — aggregation only.",
        "operationId": "getDashboardSummary",
        "responses": {
          "200": {
            "description": "Dashboard metrics",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardSummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/dashboard/report": {
      "get": {
        "tags": ["Dashboard"],
        "summary": "Download portfolio PDF report",
        "description": "Generates a PDF report covering all vendors in the portfolio. Includes overall risk summary, vendor score distribution, top findings, and responsibility tracking overview.",
        "operationId": "downloadPortfolioReport",
        "responses": {
          "200": {
            "description": "Portfolio PDF report",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/vendors/{vendorId}/frameworks/{frameworkId}/report": {
      "get": {
        "tags": ["Vendors"],
        "summary": "Download framework compliance report",
        "description": "Generates a PDF compliance report for a vendor against a specific framework. Includes a domain compliance summary (current vs previous assessment) and a per-control compliance heatmap.",
        "operationId": "downloadFrameworkReport",
        "parameters": [
          {
            "name": "vendorId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "frameworkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Framework compliance PDF report",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "authjs.session-token",
        "description": "Auth.js session token cookie. Log in via `/login` in a browser to obtain one. Works automatically when calling from the browser."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key authentication. Generate keys in Settings → API. Keys have the form `mrk_<prefix>.<secret>`; use the full value in the `Authorization` header as `Bearer mrk_<prefix>.<secret>`. Keys grant full access to every endpoint and remain valid independently of the account that created them. Keys can be IP-restricted and have configurable expiry. API key auth must be enabled by an admin first."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The request is missing valid authentication. Log in via the web app for a session cookie, or provide a valid API key via `Authorization: Bearer mrk_xxx`. API keys must be enabled by an admin (Settings → API).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Unauthorized"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The caller is authenticated but lacks the permission required for this endpoint. API keys can be scoped to specific permissions at creation (Settings → API); browser sessions inherit permissions from the user's assigned role. Ask an admin to grant the relevant permission (Settings → Roles).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Forbidden"
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested resource was not found. Verify the ID is correct.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Not found"
            }
          }
        }
      },
      "BadRequest": {
        "description": "The request body or parameters are invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Invalid vendor data."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message"
          }
        }
      },
      "AuditEntry": {
        "type": "object",
        "description": "A single audit log entry — use with SIEM tools or compliance reporting",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique audit entry ID"
          },
          "action": {
            "type": "string",
            "description": "Machine-readable action name (e.g. LOGIN, CREATE_VENDOR)",
            "example": "LOGIN"
          },
          "actionLabel": {
            "type": "string",
            "description": "Human-readable action label",
            "example": "Login"
          },
          "userName": {
            "type": "string",
            "description": "Name of the user who performed the action"
          },
          "entityType": {
            "type": "string",
            "nullable": true,
            "description": "Type of entity acted upon (e.g. Vendor, Assessment, Template)",
            "example": "Vendor"
          },
          "entityId": {
            "type": "string",
            "nullable": true,
            "description": "ID of the entity acted upon (first 8 chars)",
            "example": "cmr182ra3"
          },
          "entityName": {
            "type": "string",
            "nullable": true,
            "description": "Human-readable name of the entity"
          },
          "meta": {
            "type": "object",
            "nullable": true,
            "description": "Additional free-form metadata about the event"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 timestamp of the event"
          }
        }
      },
      "VendorSummary": {
        "type": "object",
        "description": "Lightweight vendor entry for list views",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique vendor ID"
          },
          "name": {
            "type": "string",
            "description": "Vendor name"
          },
          "externalId": {
            "type": "string",
            "nullable": true,
            "description": "Optional reference ID from an external system"
          },
          "contactName": {
            "type": "string",
            "nullable": true,
            "description": "Primary contact person"
          },
          "contactEmail": {
            "type": "string",
            "description": "Contact email address"
          },
          "tier": {
            "type": "string",
            "nullable": true,
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"],
            "description": "Risk tier classification"
          },
          "website": {
            "type": "string",
            "nullable": true,
            "description": "Vendor website URL"
          },
          "overallScore": {
            "type": "number",
            "nullable": true,
            "format": "float",
            "description": "Aggregate risk score (0–1). null when no assessments have been scored.",
            "example": 0.72
          },
          "lastAssessedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "When the vendor was last assessed"
          },
          "assessmentCount": {
            "type": "integer",
            "description": "Total number of assessments"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels for grouping and filtering"
          }
        }
      },
      "VendorDetail": {
        "type": "object",
        "description": "Full vendor profile including contact info, assessment history, and domain compliance",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "externalId": {
            "type": "string",
            "nullable": true
          },
          "contactName": {
            "type": "string",
            "nullable": true
          },
          "contactEmail": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "nullable": true,
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "overallScore": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "lastAssessedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "contractValue": {
            "type": "string",
            "nullable": true,
            "enum": ["$0–$50K", "$50K–$250K", "$250K–$1M", "$1M–$5M", "$5M+"],
            "description": "Approximate annual contract value"
          },
          "geographicRisk": {
            "type": "string",
            "nullable": true,
            "enum": [
              "DOMESTIC",
              "REGIONAL",
              "GLOBAL",
              "HIGH_RISK_JURISDICTION"
            ],
            "description": "Geographic risk classification"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels for grouping and filtering"
          },
          "assessments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "DRAFT",
                    "SENT",
                    "IN_PROGRESS",
                    "SUBMITTED",
                    "UNDER_REVIEW",
                    "COMPLETED"
                  ]
                },
                "score": {
                  "type": "number",
                  "nullable": true,
                  "format": "float"
                },
                "templateName": {
                  "type": "string",
                  "nullable": true
                },
                "templateVersion": {
                  "type": "integer",
                  "nullable": true
                }
              }
            }
          },
          "domainBreakdown": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "domain": {
                  "type": "string"
                },
                "frameworkId": {
                  "type": "string"
                },
                "frameworkName": {
                  "type": "string"
                },
                "complianceRatio": {
                  "type": "number",
                  "format": "float"
                },
                "controlCount": {
                  "type": "integer"
                }
              }
            }
          },
          "history": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "submittedAt": {
                  "type": "string",
                  "nullable": true,
                  "format": "date-time"
                },
                "score": {
                  "type": "number",
                  "nullable": true
                }
              }
            }
          },
          "customerResponsibilityCompliance": {
            "nullable": true,
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "completed": {
                "type": "integer"
              },
              "inProgress": {
                "type": "integer"
              },
              "pending": {
                "type": "integer"
              },
              "notApplicable": {
                "type": "integer"
              },
              "percent": {
                "type": "integer"
              }
            }
          }
        }
      },
      "VendorScore": {
        "type": "object",
        "description": "Lightweight score summary for dashboards and integrations",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "nullable": true
          },
          "overallScore": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "lastAssessedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "assessmentCount": {
            "type": "integer"
          },
          "latestScore": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "domainBreakdown": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "domain": {
                  "type": "string"
                },
                "frameworkId": {
                  "type": "string"
                },
                "frameworkName": {
                  "type": "string"
                },
                "complianceRatio": {
                  "type": "number"
                },
                "controlCount": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "VendorImport": {
        "type": "object",
        "required": ["name", "contactEmail"],
        "description": "Vendor data for import. Only `name` and `contactEmail` are required.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "description": "Vendor name (required)"
          },
          "externalId": {
            "type": "string",
            "description": "Optional reference ID from an external system"
          },
          "contactName": {
            "type": "string",
            "description": "Primary contact person's full name"
          },
          "contactEmail": {
            "type": "string",
            "format": "email",
            "description": "Valid contact email address (required)"
          },
          "tier": {
            "type": "string",
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"],
            "description": "Risk tier classification"
          },
          "website": {
            "type": "string",
            "description": "Vendor website URL"
          },
          "notes": {
            "type": "string",
            "description": "Free-text notes about the vendor"
          },
          "serviceDescription": {
            "type": "string",
            "description": "What the vendor provides (e.g. cloud email hosting)"
          },
          "dataSensitivity": {
            "type": "string",
            "enum": ["PUBLIC", "INTERNAL", "CONFIDENTIAL", "RESTRICTED"],
            "description": "Classification of the data the vendor handles"
          },
          "contractRenewalDate": {
            "type": "string",
            "format": "date",
            "description": "Contract renewal / review date (YYYY-MM-DD)"
          },
          "contractValue": {
            "type": "string",
            "enum": ["$0–$50K", "$50K–$250K", "$250K–$1M", "$1M–$5M", "$5M+"],
            "description": "Approximate annual contract value"
          },
          "geographicRisk": {
            "type": "string",
            "enum": [
              "DOMESTIC",
              "REGIONAL",
              "GLOBAL",
              "HIGH_RISK_JURISDICTION"
            ],
            "description": "Geographic risk classification"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels for grouping and filtering"
          }
        }
      },
      "VendorCreated": {
        "type": "object",
        "description": "The newly created vendor record",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "contactName": {
            "type": "string",
            "nullable": true
          },
          "contactEmail": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "nullable": true
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "serviceDescription": {
            "type": "string",
            "nullable": true
          },
          "dataSensitivity": {
            "type": "string",
            "nullable": true,
            "enum": ["PUBLIC", "INTERNAL", "CONFIDENTIAL", "RESTRICTED"]
          },
          "contractRenewalDate": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "contractValue": {
            "type": "string",
            "nullable": true,
            "enum": ["$0–$50K", "$50K–$250K", "$250K–$1M", "$1M–$5M", "$5M+"]
          },
          "geographicRisk": {
            "type": "string",
            "nullable": true,
            "enum": ["DOMESTIC", "REGIONAL", "GLOBAL", "HIGH_RISK_JURISDICTION"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels"
          },
          "ownerId": {
            "type": "string",
            "nullable": true
          },
          "overallScore": {
            "type": "number",
            "nullable": true
          },
          "lastAssessedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TemplateExport": {
        "type": "object",
        "description": "Full template structure exported as JSON — suitable for sharing or re-importing",
        "properties": {
          "name": {
            "type": "string",
            "description": "Template name"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Template description"
          },
          "sections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "questions": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "text": {
                        "type": "string",
                        "description": "Question text"
                      },
                      "helpText": {
                        "type": "string",
                        "nullable": true
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "YES_NO",
                          "MULTIPLE_CHOICE",
                          "FREE_TEXT",
                          "FILE_UPLOAD",
                          "DATE",
                          "NUMERIC",
                          "COMBOBOX",
                          "MULTI_SELECT",
                          "RATING"
                        ],
                        "description": "Question answer type"
                      },
                      "riskWeight": {
                        "type": "string",
                        "enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"],
                        "description": "Risk weight for scoring"
                      },
                      "required": {
                        "type": "boolean"
                      },
                      "options": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Available options for COMBOBOX/MULTIPLE_CHOICE/MULTI_SELECT"
                      },
                      "expectedAnswer": {
                        "description": "The expected compliant answer (type varies by question type)"
                      },
                      "conditionalLogic": {
                        "type": "object",
                        "nullable": true,
                        "description": "Show/hide condition referencing another question"
                      },
                      "controlCodes": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Framework control codes this question maps to"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "DeletedResponse": {
        "type": "object",
        "properties": {
          "deleted": {
            "type": "boolean"
          }
        }
      },
      "VendorUpdate": {
        "type": "object",
        "description": "Vendor fields for update. All fields are optional — omitted fields retain their existing values.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "contactName": {
            "type": "string"
          },
          "contactEmail": {
            "type": "string",
            "format": "email"
          },
          "tier": {
            "type": "string",
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
          },
          "website": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "serviceDescription": {
            "type": "string"
          },
          "dataSensitivity": {
            "type": "string",
            "enum": ["PUBLIC", "INTERNAL", "CONFIDENTIAL", "RESTRICTED"]
          },
          "contractRenewalDate": {
            "type": "string",
            "format": "date"
          },
          "contractValue": {
            "type": "string",
            "enum": ["$0–$50K", "$50K–$250K", "$250K–$1M", "$1M–$5M", "$5M+"]
          },
          "geographicRisk": {
            "type": "string",
            "enum": ["DOMESTIC", "REGIONAL", "GLOBAL", "HIGH_RISK_JURISDICTION"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels"
          },
          "ownerId": {
            "type": "string"
          }
        }
      },
      "VendorUpdated": {
        "type": "object",
        "description": "The vendor record after a successful update",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "contactName": {
            "type": "string",
            "nullable": true
          },
          "contactEmail": {
            "type": "string"
          },
          "tier": {
            "type": "string",
            "nullable": true,
            "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
          },
          "website": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "serviceDescription": {
            "type": "string",
            "nullable": true
          },
          "dataSensitivity": {
            "type": "string",
            "nullable": true,
            "enum": ["PUBLIC", "INTERNAL", "CONFIDENTIAL", "RESTRICTED"]
          },
          "contractRenewalDate": {
            "type": "string",
            "nullable": true,
            "format": "date"
          },
          "contractValue": {
            "type": "string",
            "nullable": true,
            "enum": ["$0–$50K", "$50K–$250K", "$250K–$1M", "$1M–$5M", "$5M+"]
          },
          "geographicRisk": {
            "type": "string",
            "nullable": true,
            "enum": ["DOMESTIC", "REGIONAL", "GLOBAL", "HIGH_RISK_JURISDICTION"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User-defined labels"
          },
          "ownerId": {
            "type": "string",
            "nullable": true
          },
          "overallScore": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AssessmentSummary": {
        "type": "object",
        "description": "Lightweight assessment entry for list views",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "SENT",
              "IN_PROGRESS",
              "SUBMITTED",
              "UNDER_REVIEW",
              "COMPLETED"
            ]
          },
          "score": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "dueDate": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "sentAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "submittedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "templateName": {
            "type": "string",
            "nullable": true
          },
          "templateVersion": {
            "type": "integer",
            "nullable": true
          },
          "reviewerName": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "AssessmentList": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssessmentSummary"
            }
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "totalCount": {
            "type": "integer"
          }
        }
      },
      "AssessmentDetail": {
        "type": "object",
        "description": "Full assessment detail including vendor, template, flat question list with responses, review decisions, findings, and threaded comments",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "score": {
            "type": "number",
            "nullable": true,
            "format": "float"
          },
          "dueDate": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "sentAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "submittedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "recurrence": {
            "type": "string",
            "nullable": true,
            "enum": [
              "NONE",
              "WEEKLY",
              "MONTHLY",
              "QUARTERLY",
              "BIANNUALLY",
              "ANNUALLY"
            ]
          },
          "vendor": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "contactName": {
                "type": "string",
                "nullable": true
              },
              "contactEmail": {
                "type": "string"
              },
              "tier": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "template": {
            "type": "object",
            "nullable": true,
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "integer"
              }
            }
          },
          "reviewer": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            }
          },
          "questions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "sectionTitle": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "helpText": {
                  "type": "string",
                  "nullable": true
                },
                "type": {
                  "type": "string"
                },
                "riskWeight": {
                  "type": "string"
                },
                "required": {
                  "type": "boolean"
                },
                "expectedAnswer": {
                  "type": "string",
                  "nullable": true
                },
                "options": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "nullable": true
                },
                "order": {
                  "type": "integer"
                },
                "controlIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "sharedControlIds": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "response": {
                  "type": "object",
                  "nullable": true,
                  "properties": {
                    "value": {},
                    "isNotApplicable": {
                      "type": "boolean"
                    },
                    "isCompliant": {
                      "type": "boolean"
                    },
                    "weightedScore": {
                      "type": "number",
                      "nullable": true
                    },
                    "maxScore": {
                      "type": "number",
                      "nullable": true
                    },
                    "review": {
                      "type": "object",
                      "nullable": true,
                      "properties": {
                        "decision": {
                          "type": "string"
                        },
                        "note": {
                          "type": "string",
                          "nullable": true
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "findings": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string",
                  "nullable": true
                },
                "severity": {
                  "type": "string",
                  "enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
                },
                "status": {
                  "type": "string",
                  "enum": ["OPEN", "REMEDIATED", "RISK_ACCEPTED"]
                },
                "controlCodes": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "resolutionNote": {
                  "type": "string",
                  "nullable": true
                },
                "resolvedAt": {
                  "type": "string",
                  "nullable": true,
                  "format": "date-time"
                },
                "resolvedByName": {
                  "type": "string",
                  "nullable": true
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          },
          "comments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "authorType": {
                  "type": "string"
                },
                "authorName": {
                  "type": "string"
                },
                "body": {
                  "type": "string"
                },
                "visibility": {
                  "type": "string",
                  "enum": ["INTERNAL", "SHARED", "VENDOR_ONLY"]
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                },
                "replies": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "authorType": {
                        "type": "string"
                      },
                      "authorName": {
                        "type": "string"
                      },
                      "body": {
                        "type": "string"
                      },
                      "visibility": {
                        "type": "string",
                        "enum": ["INTERNAL", "SHARED", "VENDOR_ONLY"]
                      },
                      "createdAt": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "VendorAssessmentList": {
        "type": "object",
        "properties": {
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssessmentSummary"
            }
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "totalCount": {
            "type": "integer"
          }
        }
      },
      "CertificationSummary": {
        "type": "object",
        "description": "A vendor certification record",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "issuer": {
            "type": "string",
            "nullable": true
          },
          "issuedDate": {
            "type": "string",
            "nullable": true,
            "format": "date"
          },
          "expiresDate": {
            "type": "string",
            "nullable": true,
            "format": "date"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "fileName": {
                  "type": "string"
                },
                "displayName": {
                  "type": "string",
                  "nullable": true
                },
                "mimeType": {
                  "type": "string"
                },
                "sizeBytes": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "CertificationList": {
        "type": "object",
        "properties": {
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CertificationSummary"
            }
          }
        }
      },
      "FindingSummary": {
        "type": "object",
        "description": "A finding raised from an assessment response",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "severity": {
            "type": "string",
            "enum": ["CRITICAL", "HIGH", "MEDIUM", "LOW"]
          },
          "status": {
            "type": "string",
            "enum": ["OPEN", "REMEDIATED", "RISK_ACCEPTED"]
          },
          "controlCodes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "resolutionNote": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "assessmentId": {
            "type": "string"
          },
          "assessmentTitle": {
            "type": "string"
          },
          "vendorId": {
            "type": "string"
          },
          "vendorName": {
            "type": "string"
          }
        }
      },
      "FindingList": {
        "type": "object",
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FindingSummary"
            }
          },
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "totalCount": {
            "type": "integer"
          }
        }
      },
      "FindingStatusUpdate": {
        "type": "object",
        "required": ["status"],
        "description": "Payload to update a finding's status",
        "properties": {
          "status": {
            "type": "string",
            "enum": ["REMEDIATED", "RISK_ACCEPTED"],
            "description": "New status for the finding"
          },
          "resolutionNote": {
            "type": "string",
            "description": "Explanation for the status change"
          }
        }
      },
      "FindingUpdated": {
        "type": "object",
        "description": "The finding record after a status update",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "resolutionNote": {
            "type": "string",
            "nullable": true
          },
          "resolvedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          }
        }
      },
      "FrameworkSummary": {
        "type": "object",
        "description": "Lightweight framework entry for list views",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "controlCount": {
            "type": "integer"
          }
        }
      },
      "FrameworkDetail": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "controls": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ControlSummary"
            }
          }
        }
      },
      "ControlSummary": {
        "type": "object",
        "description": "A single framework control",
        "properties": {
          "id": {
            "type": "string"
          },
          "domain": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "guidance": {
            "type": "string",
            "nullable": true
          },
          "order": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "DashboardSummary": {
        "type": "object",
        "description": "Aggregated portfolio metrics for dashboards and BI tools",
        "properties": {
          "vendors": {
            "type": "integer",
            "description": "Total vendor count"
          },
          "vendorCount": {
            "type": "integer",
            "description": "Alias for vendors"
          },
          "averageScore": {
            "type": "number",
            "nullable": true,
            "format": "float",
            "description": "Portfolio-wide average score (0–1)"
          },
          "openFindings": {
            "type": "integer",
            "description": "Count of open findings across the portfolio"
          },
          "needsAttention": {
            "type": "integer",
            "description": "Vendors with status overdue or score below threshold"
          },
          "scoreDistribution": {
            "type": "object",
            "description": "RAG score distribution counts",
            "properties": {
              "green": {
                "type": "integer"
              },
              "amber": {
                "type": "integer"
              },
              "red": {
                "type": "integer"
              },
              "unscored": {
                "type": "integer"
              }
            }
          },
          "topDeficientControls": {
            "type": "array",
            "description": "Top 10 most-failed controls across the portfolio",
            "items": {
              "type": "object",
              "properties": {
                "controlCode": {
                  "type": "string"
                },
                "controlTitle": {
                  "type": "string"
                },
                "failCount": {
                  "type": "integer"
                }
              }
            }
          },
          "riskByTier": {
            "type": "array",
            "description": "Vendor count by risk tier",
            "items": {
              "type": "object",
              "properties": {
                "tier": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "assessmentStatusCounts": {
            "type": "object",
            "description": "Assessment count by status",
            "properties": {
              "COMPLETED": {
                "type": "integer"
              },
              "IN_PROGRESS": {
                "type": "integer"
              },
              "OVERDUE": {
                "type": "integer"
              },
              "UNDER_REVIEW": {
                "type": "integer"
              },
              "SENT": {
                "type": "integer"
              },
              "DRAFT": {
                "type": "integer"
              },
              "SUBMITTED": {
                "type": "integer"
              }
            }
          },
          "vendorsByTier": {
            "type": "object",
            "description": "Vendor count by tier (keyed by tier name)",
            "properties": {
              "LOW": {
                "type": "integer"
              },
              "MEDIUM": {
                "type": "integer"
              },
              "HIGH": {
                "type": "integer"
              },
              "CRITICAL": {
                "type": "integer"
              }
            }
          },
          "customerResponsibilitySummary": {
            "nullable": true,
            "type": "object",
            "description": "Aggregated customer responsibility compliance across all vendors",
            "properties": {
              "totalVendors": {
                "type": "integer"
              },
              "totalActions": {
                "type": "integer"
              },
              "completedActions": {
                "type": "integer"
              },
              "percent": {
                "type": "integer"
              }
            }
          }
        }
      }
    }
  }
}
