{
  "openapi": "3.1.0",
  "info": {
    "title": "Nexus CRM API",
    "version": "1.0.0",
    "description": "REST API for the Nexus CRM application.\n\n## Authentication\n\nTwo auth methods are supported:\n\n- **BearerAuth** – `Authorization: Bearer <token>`. Per-user API token generated in the dashboard. Scoped to the token owner's data (admin tokens get cross-tenant read access).\n- **CookieAuth** – Session cookie set by the Better Auth `/api/auth` flow (Google OAuth).\n\nToken management (POST/DELETE `/api/token`) requires a session cookie. The file download endpoint also accepts a `PUBLIC_READ_TOKEN` query parameter for share links."
  },
  "servers": [
    {
      "url": "/",
      "description": "Current host"
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Per-user API token generated via the dashboard (POST /api/token). Scoped to the token owner's data. Admin users' tokens get cross-tenant read access."
      },
      "CookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "better-auth.session_token",
        "description": "Session cookie issued by the Better Auth flow at `/api/auth`. Admin users (isAdmin=true) bypass per-user filtering."
      }
    },
    "schemas": {
      "ApplicationStatus": {
        "type": "string",
        "enum": ["inbound", "applied", "interview", "offer", "rejected"],
        "description": "Current stage of the opportunity pipeline."
      },
      "ContactRef": {
        "type": "object",
        "description": "A contact person associated with an application.",
        "required": ["id", "name", "applicationId", "createdAt"],
        "properties": {
          "id":            { "type": "integer", "example": 1 },
          "name":          { "type": "string",  "example": "Jane Smith" },
          "email":         { "type": ["string", "null"], "format": "email", "example": "jane@example.com" },
          "phone":         { "type": ["string", "null"], "example": "+1-555-0100" },
          "role":          { "type": ["string", "null"], "example": "Engineering Manager" },
          "linkedIn":      { "type": ["string", "null"], "example": "https://linkedin.com/in/janesmith" },
          "applicationId": { "type": "integer", "example": 42 },
          "createdAt":     { "type": "string",  "format": "date-time" }
        }
      },
      "ApplicationRef": {
        "type": "object",
        "description": "Minimal application reference (used inside Document).",
        "required": ["id", "company", "role"],
        "properties": {
          "id":      { "type": "integer", "example": 42 },
          "company": { "type": "string",  "example": "Acme Corp" },
          "role":    { "type": "string",  "example": "Senior Engineer" }
        }
      },
      "Application": {
        "type": "object",
        "description": "An opportunity record.",
        "required": ["id", "userId", "company", "role", "status", "createdAt", "updatedAt", "contacts"],
        "properties": {
          "id":             { "type": "integer",              "example": 42 },
          "userId":         { "type": "string",               "example": "user_abc123" },
          "company":        { "type": "string",               "example": "Acme Corp" },
          "role":           { "type": "string",               "example": "Senior Engineer" },
          "status":         { "$ref": "#/components/schemas/ApplicationStatus" },
          "appliedAt":      { "type": ["string", "null"],     "format": "date-time" },
          "lastContact":    { "type": ["string", "null"],     "format": "date-time" },
          "followUpAt":     { "type": ["string", "null"],     "format": "date-time" },
          "notes":          { "type": ["string", "null"],     "example": "Had a great first call." },
          "jobDescription": { "type": ["string", "null"],     "example": "We are looking for…" },
          "createdAt":      { "type": "string",               "format": "date-time" },
          "updatedAt":      { "type": "string",               "format": "date-time" },
          "contacts":       {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ContactRef" }
          }
        }
      },
      "Document": {
        "type": "object",
        "description": "An uploaded document (PDF, image) attached to one or more applications.",
        "required": ["id", "userId", "filename", "originalName", "size", "mimeType", "uploadedAt", "applications"],
        "properties": {
          "id":           { "type": "integer", "example": 7 },
          "userId":       { "type": "string",  "example": "user_abc123" },
          "filename":     { "type": "string",  "example": "3f2504e0-4f89-11d3-9a0c-0305e82c3301.pdf", "description": "UUID-based filename on disk." },
          "originalName": { "type": "string",  "example": "my-resume.pdf" },
          "size":         { "type": "integer", "example": 204800, "description": "File size in bytes." },
          "mimeType":     { "type": "string",  "example": "application/pdf", "enum": ["application/pdf", "image/jpeg", "image/png", "image/webp"] },
          "uploadedAt":   { "type": "string",  "format": "date-time" },
          "applications": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApplicationRef" }
          }
        }
      },
      "UserRecord": {
        "type": "object",
        "description": "A registered user.",
        "required": ["id", "name", "email", "isAdmin"],
        "properties": {
          "id":      { "type": "string",  "example": "user_abc123" },
          "name":    { "type": ["string", "null"], "example": "Jane Doe" },
          "email":   { "type": "string",  "format": "email", "example": "jane@example.com" },
          "isAdmin": { "type": "boolean", "example": false, "description": "Whether the user has admin privileges (sees all tenants)." }
        }
      },
      "ApiTokenInfo": {
        "type": "object",
        "description": "API token metadata (never includes the raw token).",
        "required": ["id", "name", "createdAt", "lastUsedAt"],
        "properties": {
          "id":         { "type": "string",          "example": "1" },
          "name":       { "type": "string",          "example": "default" },
          "createdAt":  { "type": "string",          "format": "date-time" },
          "lastUsedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string", "example": "Unauthorized" }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "required": ["success"],
        "properties": {
          "success": { "type": "boolean", "example": true }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid credentials.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": { "error": "Unauthorized" }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient permissions — admin privileges required or resource does not belong to the authenticated user.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": { "error": "Session required" }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found or does not belong to the authenticated user.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" },
            "example": { "error": "Not found" }
          }
        }
      },
      "BadRequest": {
        "description": "Invalid or missing request parameters.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ErrorResponse" }
          }
        }
      }
    }
  },
  "paths": {
    "/api/applications": {
      "get": {
        "operationId": "listApplications",
        "summary": "List applications",
        "description": "Returns all applications for the authenticated user, ordered by creation date descending. Admin users see all applications across tenants.",
        "tags": ["Applications"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Array of applications (with embedded contacts).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Application" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "createApplication",
        "summary": "Create application",
        "description": "Creates a new application owned by the session user.",
        "tags": ["Applications"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["company", "role"],
                "properties": {
                  "company":        { "type": "string", "maxLength": 255, "example": "Acme Corp" },
                  "role":           { "type": "string", "maxLength": 255, "example": "Senior Engineer" },
                  "status":         { "$ref": "#/components/schemas/ApplicationStatus" },
                  "appliedAt":      { "type": ["string", "null"], "format": "date-time" },
                  "lastContact":    { "type": ["string", "null"], "format": "date-time" },
                  "followUpAt":     { "type": ["string", "null"], "format": "date-time" },
                  "notes":          { "type": ["string", "null"], "maxLength": 10000 },
                  "jobDescription": { "type": ["string", "null"], "maxLength": 50000 }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Newly created application.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Application" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/applications/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Application ID."
        }
      ],
      "get": {
        "operationId": "getApplication",
        "summary": "Get application",
        "description": "Returns a single application by ID. Access is scoped to the authenticated user (admin users see all).",
        "tags": ["Applications"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "The application.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Application" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "operationId": "updateApplication",
        "summary": "Update application",
        "description": "Partially updates an application. All fields are optional. **Requires a session.**",
        "tags": ["Applications"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "company":        { "type": "string", "maxLength": 255 },
                  "role":           { "type": "string", "maxLength": 255 },
                  "status":         { "$ref": "#/components/schemas/ApplicationStatus" },
                  "appliedAt":      { "type": ["string", "null"], "format": "date-time" },
                  "lastContact":    { "type": ["string", "null"], "format": "date-time" },
                  "followUpAt":     { "type": ["string", "null"], "format": "date-time" },
                  "notes":          { "type": ["string", "null"], "maxLength": 10000 },
                  "jobDescription": { "type": ["string", "null"], "maxLength": 50000 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated application.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Application" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteApplication",
        "summary": "Delete application",
        "description": "Deletes an application and its related contacts. **Requires a session.**",
        "tags": ["Applications"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Deletion confirmed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SuccessResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/applications/{id}/contacts": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Application ID."
        }
      ],
      "post": {
        "operationId": "createContact",
        "summary": "Add contact to application",
        "description": "Creates a contact associated with the given application. **Requires a session.** The application must belong to the authenticated user.",
        "tags": ["Contacts"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name":     { "type": "string", "maxLength": 255,  "example": "Jane Smith" },
                  "email":    { "type": ["string", "null"], "format": "email", "maxLength": 255 },
                  "phone":    { "type": ["string", "null"], "maxLength": 50 },
                  "role":     { "type": ["string", "null"], "maxLength": 100, "example": "Recruiter" },
                  "linkedIn": { "type": ["string", "null"], "maxLength": 500, "example": "https://linkedin.com/in/janesmith" }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Newly created contact.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContactRef" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/applications/{id}/contacts/{contactId}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Application ID."
        },
        {
          "name": "contactId",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Contact ID."
        }
      ],
      "patch": {
        "operationId": "updateContact",
        "summary": "Update contact",
        "description": "Partially updates a contact. All fields are optional. **Requires a session.** The parent application must belong to the authenticated user.",
        "tags": ["Contacts"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name":     { "type": "string",          "maxLength": 255 },
                  "email":    { "type": ["string", "null"], "format": "email", "maxLength": 255 },
                  "phone":    { "type": ["string", "null"], "maxLength": 50 },
                  "role":     { "type": ["string", "null"], "maxLength": 100 },
                  "linkedIn": { "type": ["string", "null"], "maxLength": 500 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated contact.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContactRef" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteContact",
        "summary": "Delete contact",
        "description": "Deletes a contact. **Requires a session.** The parent application must belong to the authenticated user.",
        "tags": ["Contacts"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Deletion confirmed.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SuccessResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/documents": {
      "get": {
        "operationId": "listDocuments",
        "summary": "List documents",
        "description": "Returns all documents for the authenticated user, ordered by upload date descending. Each document includes its linked applications. Admin users see all documents.",
        "tags": ["Documents"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Array of documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Document" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "uploadDocument",
        "summary": "Upload document",
        "description": "Uploads a file (PDF, JPEG, PNG, or WEBP; max 10 MB). Optionally links the document to one or more applications owned by the session user. **Requires a session.**",
        "tags": ["Documents"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": ["file"],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The file to upload. Allowed MIME types: `application/pdf`, `image/jpeg`, `image/png`, `image/webp`. Maximum size: 10 MB."
                  },
                  "applicationIds": {
                    "type": "string",
                    "description": "JSON-encoded array of application IDs to link, e.g. `[1, 2, 3]`.",
                    "example": "[42, 43]"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Uploaded document record.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Document" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "413": {
            "description": "File exceeds the 10 MB size limit.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": { "error": "File too large (max 10 MB)" }
              }
            }
          },
          "415": {
            "description": "Unsupported file type.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ErrorResponse" },
                "example": { "error": "Unsupported file type. Allowed: PDF, JPEG, PNG, WEBP" }
              }
            }
          }
        }
      }
    },
    "/api/documents/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Document ID."
        }
      ],
      "patch": {
        "operationId": "updateDocumentLinks",
        "summary": "Update document application links",
        "description": "Replaces the set of applications linked to this document. Provide a complete `applicationIds` array — this is a *set* operation, not a merge. **Requires a session.**",
        "tags": ["Documents"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["applicationIds"],
                "properties": {
                  "applicationIds": {
                    "type": "array",
                    "items": { "type": "integer" },
                    "description": "Complete list of application IDs to link. Only IDs owned by the session user are accepted.",
                    "example": [42, 43]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated document with new application links.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Document" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "delete": {
        "operationId": "deleteDocument",
        "summary": "Delete document",
        "description": "Deletes the document record and removes the file from disk. **Requires a session.**",
        "tags": ["Documents"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "204": {
            "description": "Document deleted. No response body."
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/documents/{id}/file": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "integer", "minimum": 1 },
          "description": "Document ID."
        }
      ],
      "get": {
        "operationId": "downloadDocumentFile",
        "summary": "Download document file",
        "description": "Streams the raw file with the original filename as the download name.\n\nAccess is permitted via any of:\n- Session cookie (`CookieAuth`)\n- `?token=<PUBLIC_READ_TOKEN>` query parameter (share links / readonly embeds)\n\nThe public token is obtained from `GET /api/config/public-token`.",
        "tags": ["Documents"],
        "security": [
          { "CookieAuth": [] },
          {}
        ],
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Public read token (`PUBLIC_READ_TOKEN`). Allows unauthenticated file access for share links."
          }
        ],
        "responses": {
          "200": {
            "description": "Raw file binary. `Content-Type` reflects the stored MIME type.",
            "content": {
              "application/pdf":  { "schema": { "type": "string", "format": "binary" } },
              "image/jpeg":       { "schema": { "type": "string", "format": "binary" } },
              "image/png":        { "schema": { "type": "string", "format": "binary" } },
              "image/webp":       { "schema": { "type": "string", "format": "binary" } }
            },
            "headers": {
              "Content-Disposition": {
                "schema": { "type": "string" },
                "description": "e.g. `attachment; filename=\"my-resume.pdf\"`"
              },
              "Content-Length": {
                "schema": { "type": "integer" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/token": {
      "get": {
        "operationId": "getApiToken",
        "summary": "Get current API token info",
        "description": "Returns metadata about the authenticated user's API token, or null if none exists. Does not return the raw token.",
        "tags": ["Token"],
        "security": [
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Token metadata or null.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "oneOf": [
                        { "$ref": "#/components/schemas/ApiTokenInfo" },
                        { "type": "null" }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "post": {
        "operationId": "createApiToken",
        "summary": "Generate a new API token",
        "description": "Generates a new per-user API token. If a token already exists, it is revoked first. The raw token is returned only once in the response. **Requires a session** (Bearer tokens cannot create new tokens).",
        "tags": ["Token"],
        "security": [
          { "CookieAuth": [] }
        ],
        "responses": {
          "201": {
            "description": "Newly created token. The `raw` field contains the token value (shown only once).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["raw", "token"],
                  "properties": {
                    "raw":   { "type": "string", "example": "jt_abc123...", "description": "The raw API token. Copy it now — it will not be shown again." },
                    "token": { "$ref": "#/components/schemas/ApiTokenInfo" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      },
      "delete": {
        "operationId": "revokeApiToken",
        "summary": "Revoke API token",
        "description": "Revokes the authenticated user's API token. **Requires a session.**",
        "tags": ["Token"],
        "security": [
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Token revoked.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SuccessResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    },
    "/api/users": {
      "get": {
        "operationId": "listUsers",
        "summary": "List all users",
        "description": "Returns all registered users. **Requires admin privileges.**",
        "tags": ["Admin"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "Array of users.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/UserRecord" }
                }
              }
            }
          },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/api/users/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": { "type": "string" },
          "description": "User ID."
        }
      ],
      "patch": {
        "operationId": "updateUserAdmin",
        "summary": "Update user admin status",
        "description": "Sets or revokes admin privileges for a user. Cannot remove the last admin. **Requires admin privileges.**",
        "tags": ["Admin"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["isAdmin"],
                "properties": {
                  "isAdmin": { "type": "boolean", "description": "Whether the user should have admin privileges." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/UserRecord" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/api/config/public-token": {
      "get": {
        "operationId": "getPublicToken",
        "summary": "Get public read token",
        "description": "Returns the `PUBLIC_READ_TOKEN` so authenticated clients can construct shareable file download URLs without the token being exposed in the JavaScript bundle. **Requires a session** (cookie auth only).",
        "tags": ["Config"],
        "security": [
          { "BearerAuth": [] },
          { "CookieAuth": [] }
        ],
        "responses": {
          "200": {
            "description": "The public read token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["token"],
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "Value of the `PUBLIC_READ_TOKEN` env var. Pass as `?token=<value>` to `GET /api/documents/{id}/file`.",
                      "example": "pub_abc123"
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        }
      }
    }
  },
  "tags": [
    { "name": "Applications", "description": "Opportunity pipeline management." },
    { "name": "Contacts",     "description": "Contacts associated with opportunities." },
    { "name": "Documents",    "description": "File uploads linked to applications." },
    { "name": "Config",       "description": "Client-side configuration endpoints." },
    { "name": "Token",        "description": "Per-user API token management." },
    { "name": "Admin",        "description": "User management (requires isAdmin=true)." }
  ]
}
