{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.org/research-atlas.schema.json",
  "title": "Research Atlas Dataset",
  "type": "object",
  "required": [
    "schemaVersion",
    "generatedAt",
    "collectionPolicy",
    "professors",
    "labs"
  ],
  "properties": {
    "schemaVersion": {
      "type": "string"
    },
    "generatedAt": {
      "type": "string"
    },
    "datasetName": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "collectionPolicy": {
      "type": "object",
      "required": [
        "publicPagesOnly",
        "recruitingClaimsRequireExplicitEvidence",
        "unknownMeansNoExplicitStatementCaptured"
      ],
      "properties": {
        "publicPagesOnly": {
          "type": "boolean"
        },
        "recruitingClaimsRequireExplicitEvidence": {
          "type": "boolean"
        },
        "unknownMeansNoExplicitStatementCaptured": {
          "type": "boolean"
        },
        "studentPrivacyBoundary": {
          "type": "string"
        }
      }
    },
    "professors": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/professor"
      }
    },
    "labs": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/lab"
      }
    },
    "qualityMigrationVersion": {
      "const": 1
    },
    "dataQuality": {
      "type": "object"
    }
  },
  "$defs": {
    "urlOrMissing": {
      "type": "string",
      "pattern": "^(https?://|Not found$|Unknown$)"
    },
    "emailOrMissing": {
      "type": "string",
      "pattern": "^([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|Not found|Unknown)$"
    },
    "recruitingStatus": {
      "type": "string",
      "enum": [
        "Recruiting",
        "Not recruiting",
        "Unknown"
      ]
    },
    "recruitingEvidence": {
      "type": "object",
      "required": [
        "text",
        "url"
      ],
      "properties": {
        "text": {
          "type": "string"
        },
        "url": {
          "type": "string"
        }
      }
    },
    "sourceUrls": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "pattern": "^https?://"
      }
    },
    "professor": {
      "type": "object",
      "required": [
        "id",
        "name",
        "institution",
        "department",
        "officialProfileUrl",
        "personalWebsiteUrl",
        "email",
        "researchAreas",
        "researchSummary",
        "googleScholarUrl",
        "labAffiliation",
        "recruitingStatus",
        "recruitingEvidence",
        "sourceUrls",
        "lastVerified",
        "fieldEvidence",
        "verification"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "institution": {
          "type": "string",
          "minLength": 1
        },
        "department": {
          "type": "string",
          "minLength": 1
        },
        "departments": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "mergedProfessorIds": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "officialProfileUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "personalWebsiteUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "email": {
          "$ref": "#/$defs/emailOrMissing"
        },
        "researchAreas": {
          "type": "array",
          "minItems": 0,
          "items": {
            "type": "string"
          }
        },
        "researchSummary": {
          "type": "string",
          "minLength": 1
        },
        "googleScholarUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "externalProfiles": {
          "$ref": "#/$defs/externalProfiles"
        },
        "googleScholarSearchUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "linkedinSearchUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "possibleScholarSourceUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "academicProfile": {
          "$ref": "#/$defs/academicProfile"
        },
        "labAffiliation": {
          "type": "string"
        },
        "labAffiliationUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "recruitingStatus": {
          "$ref": "#/$defs/recruitingStatus"
        },
        "recruitingEvidence": {
          "$ref": "#/$defs/recruitingEvidence"
        },
        "sourceUrls": {
          "$ref": "#/$defs/sourceUrls"
        },
        "lastVerified": {
          "type": "string"
        },
        "fieldEvidence": {
          "$ref": "#/$defs/fieldEvidence"
        },
        "verification": {
          "$ref": "#/$defs/verification"
        },
        "unverifiedFields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "teaching": {
          "$ref": "#/$defs/teaching"
        },
        "ratings": {
          "type": "object",
          "properties": {
            "rateMyPI": {
              "$ref": "#/$defs/rating"
            },
            "rateMyProfessors": {
              "$ref": "#/$defs/rating"
            }
          }
        },
        "researchKeywords": {
          "type": "array",
          "items": { "type": "string", "minLength": 1 },
          "description": "Research keywords the person lists on their official UCSD Profiles page. Searchable; only controlled-vocabulary matches become researchAreas."
        }
      }
    },
    "academicProfile": {
      "type": "object",
      "properties": {
        "source": {
          "type": "string"
        },
        "openAlexAuthorId": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "openAlexUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "semanticScholarAuthorId": {
          "type": ["string", "null"]
        },
        "semanticScholarUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "matchedName": {
          "type": "string"
        },
        "matchConfidence": {
          "type": "number"
        },
        "worksCount": {
          "type": [
            "number",
            "string"
          ]
        },
        "citationCount": {
          "type": [
            "number",
            "string"
          ]
        },
        "hIndex": {
          "type": [
            "number",
            "string"
          ]
        },
        "i10Index": {
          "type": [
            "number",
            "string"
          ]
        },
        "recentPublications": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string"
              },
              "year": {
                "type": [
                  "number",
                  "string"
                ]
              },
              "publicationDate": {
                "type": "string"
              },
              "citationCount": {
                "type": [
                  "number",
                  "string"
                ]
              },
              "venue": {
                "type": "string"
              },
              "url": {
                "$ref": "#/$defs/urlOrMissing"
              },
              "doi": {
                "$ref": "#/$defs/urlOrMissing"
              },
              "openAlexUrl": {
                "$ref": "#/$defs/urlOrMissing"
              },
              "semanticScholarUrl": {
                "$ref": "#/$defs/urlOrMissing"
              },
              "journalImpactFactor": {
                "$ref": "#/$defs/journalImpactFactor"
              },
              "source": {
                "type": "string"
              }
            }
          }
        },
        "metricSources": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "source": {
                "type": "string"
              },
              "url": {
                "$ref": "#/$defs/urlOrMissing"
              },
              "matchConfidence": {
                "type": ["number", "string"]
              },
              "lastVerified": {
                "type": "string"
              }
            }
          }
        },
        "lastVerified": {
          "type": "string"
        }
      }
    },
    "externalProfiles": {
      "type": "object",
      "properties": {
        "googleScholar": {
          "$ref": "#/$defs/externalProfile"
        },
        "linkedin": {
          "$ref": "#/$defs/externalProfile"
        }
      }
    },
    "externalProfile": {
      "type": "object",
      "properties": {
        "profileUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "searchUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "status": {
          "type": "string",
          "enum": [
            "confirmed",
            "candidate_search",
            "not_found",
            "blocked",
            "unavailable"
          ]
        },
        "sourceUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "lastChecked": {
          "type": "string"
        }
      }
    },
    "journalImpactFactor": {
      "type": "object",
      "properties": {
        "value": {
          "type": ["number", "string"]
        },
        "year": {
          "type": ["number", "string"]
        },
        "source": {
          "type": "string"
        },
        "status": {
          "type": "string",
          "enum": [
            "confirmed",
            "unavailable_open_data",
            "not_found",
            "unknown"
          ]
        }
      }
    },
    "lab": {
      "type": "object",
      "required": [
        "id",
        "labName",
        "institution",
        "department",
        "labWebsiteUrl",
        "principalInvestigator",
        "researchAreas",
        "description",
        "contactEmail",
        "recruitingStatus",
        "recruitingEvidence",
        "sourceUrls",
        "lastVerified",
        "fieldEvidence",
        "verification"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "labName": {
          "type": "string",
          "minLength": 1
        },
        "institution": {
          "type": "string",
          "minLength": 1
        },
        "department": {
          "type": "string",
          "minLength": 1
        },
        "departments": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "mergedLabIds": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "labWebsiteUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "principalInvestigator": {
          "type": "string"
        },
        "principalInvestigatorProfileUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "researchAreas": {
          "type": "array",
          "minItems": 0,
          "items": {
            "type": "string"
          }
        },
        "description": {
          "type": "string",
          "minLength": 1
        },
        "contactEmail": {
          "$ref": "#/$defs/emailOrMissing"
        },
        "recruitingStatus": {
          "$ref": "#/$defs/recruitingStatus"
        },
        "recruitingEvidence": {
          "$ref": "#/$defs/recruitingEvidence"
        },
        "sourceUrls": {
          "$ref": "#/$defs/sourceUrls"
        },
        "lastVerified": {
          "type": "string"
        },
        "recordSubtype": {
          "type": "string",
          "enum": [
            "lab",
            "personal_research_site",
            "research_group",
            "research_area",
            "center",
            "program",
            "contact"
          ]
        },
        "entityType": {
          "type": "string"
        },
        "coverageStatus": {
          "type": "string",
          "enum": [
            "entity_verified",
            "overview_only",
            "needs_source_review"
          ]
        },
        "discoveryMethod": {
          "type": "string"
        },
        "confidence": {
          "type": "string"
        },
        "piCandidates": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "overviewSourceUrl": {
          "$ref": "#/$defs/urlOrMissing"
        },
        "legacyKind": {
          "type": "string"
        },
        "fieldEvidence": {
          "$ref": "#/$defs/fieldEvidence"
        },
        "verification": {
          "$ref": "#/$defs/verification"
        },
        "unverifiedFields": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "aiLabScore": {
          "type": "object",
          "description": "Gemini's 0-100 judgment of whether labWebsiteUrl is a lab site: 75-100 lab, 50-74 maybe, 25-49 not a lab, 0-24 unreachable. From data/ucsd/lab-ai-scores.json.",
          "required": ["score", "category"],
          "properties": {
            "score": { "type": "integer", "minimum": 0, "maximum": 100 },
            "category": { "enum": ["lab", "maybe_lab", "not_lab", "unreachable"] },
            "reason": { "type": "string" },
            "retrievalStatus": { "type": ["string", "null"] },
            "model": { "type": "string" },
            "observedAt": { "type": "string" }
          }
        }
      }
    },
    "fieldEvidence": {
      "type": "object",
      "additionalProperties": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "required": [
            "sourceUrl",
            "observedAt",
            "evidence"
          ],
          "properties": {
            "sourceUrl": {
              "type": "string",
              "pattern": "^https?://[^/]"
            },
            "observedAt": {
              "type": "string",
              "format": "date-time"
            },
            "evidence": {
              "type": "string",
              "minLength": 1
            },
            "method": {
              "type": "string"
            }
          }
        }
      }
    },
    "verification": {
      "type": "object",
      "required": [
        "status",
        "fieldsVerified"
      ],
      "properties": {
        "status": {
          "enum": [
            "source_checked",
            "needs_review",
            "unavailable",
            "legacy_unverified"
          ]
        },
        "fieldsVerified": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "lastAttemptedAt": {
          "type": [
            "string",
            "null"
          ]
        },
        "lastEvidenceAt": {
          "type": "string"
        }
      }
    },
    "course": {
      "type": "object",
      "required": [
        "courseCode",
        "term",
        "status",
        "sourceUrl",
        "observedAt",
        "evidence"
      ],
      "properties": {
        "courseCode": {
          "type": "string",
          "minLength": 1
        },
        "title": {
          "type": [
            "string",
            "null"
          ]
        },
        "term": {
          "type": "string",
          "minLength": 1
        },
        "status": {
          "enum": [
            "historical",
            "scheduled",
            "undated",
            "current",
            "planned",
            "tentative"
          ]
        },
        "sourceUrl": {
          "type": "string",
          "pattern": "^https?://[^/]"
        },
        "observedAt": {
          "type": "string",
          "format": "date-time"
        },
        "evidence": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "teaching": {
      "type": "object",
      "required": [
        "status",
        "courses"
      ],
      "properties": {
        "status": {
          "enum": [
            "verified",
            "needs_review",
            "not_checked",
            "not_found",
            "unavailable"
          ]
        },
        "lastChecked": {
          "type": [
            "string",
            "null"
          ]
        },
        "courses": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/course"
          }
        },
        "candidates": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/course"
          }
        }
      }
    },
    "rating": {
      "type": "object",
      "required": [
        "platform",
        "status",
        "score",
        "reviewCount",
        "scale"
      ],
      "properties": {
        "platform": {
          "type": "string"
        },
        "status": {
          "enum": [
            "verified",
            "no_reviews",
            "not_checked",
            "not_found",
            "unavailable",
            "needs_review"
          ]
        },
        "score": {
          "type": [
            "number",
            "null"
          ],
          "minimum": 1,
          "maximum": 5
        },
        "scale": {
          "const": 5
        },
        "reviewCount": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0
        },
        "sourceUrl": {
          "type": [
            "string",
            "null"
          ]
        },
        "evidenceUrl": {
          "type": [
            "string",
            "null"
          ]
        },
        "observedAt": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "status": {
                "const": "verified"
              }
            }
          },
          "then": {
            "required": [
              "sourceUrl",
              "observedAt"
            ],
            "properties": {
              "score": {
                "type": "number",
                "minimum": 1,
                "maximum": 5
              },
              "reviewCount": {
                "type": "integer",
                "minimum": 1
              },
              "sourceUrl": {
                "type": "string",
                "pattern": "^https?://[^/]"
              },
              "observedAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "else": {
            "properties": {
              "score": {
                "type": "null"
              }
            }
          }
        }
      ]
    }
  }
}
