$schema: https://json-schema.org/draft/2020-12/schema
$comment: >
  Schema for a machine-readable resume / curriculum vitae.
  Canonical instance: https://dan.barvitsky.org/resume.yaml

type: object
properties:
  person: {$ref: "#/$defs/Person"}
  employment: {type: array, items: {$ref: "#/$defs/Employment"}}
  education: {type: array, items: {$ref: "#/$defs/Education"}}
  qualifications: {type: array, items: {$ref: "#/$defs/SkillCategory"}}
  availability: {$ref: "#/$defs/Availability"}

$defs:

  WebUrl:
    $comment: RFC3986-compatible URL, http or https
    type: string
    pattern: "^https?://.+"

  TrimmedText:
    $comment: Non-empty string with no leading or trailing whitespace
    type: string
    pattern: "^[^\\s].*[^\\s]$"

  Description:
    $comment: >
      Free-form text, potentially multi-line. May have trailing newline (YAML block scalars).
      Must be non-empty.
    type: string
    minLength: 1

  Place:
    $comment: >
      Geographic location as understood by humans: "City, State" (US implied) or
      "City, Country". Multi-word names such as "East Hampton, MA" are supported.
    type: string
    pattern: "^[A-Z][A-Za-z0-9 \\-]+(, [A-Z][A-Za-z0-9 \\-]+)+$"

  Iso8601DateRef:
    $comment: >
      ISO-8601 date reference: YYYY, YYYY-MM, or YYYY-MM-DD.
      MM is 01–12, DD is 01–31. Can also be the literal "present".
    type: string
    pattern: "^(\\d{4}(-\\d{2}(-\\d{2})?)?|present)$"

  DateInterval:
    $comment: A time span. `from` is the inclusive start; `to` is exclusive end or "present".
    type: object
    properties:
      from: {$ref: "#/$defs/Iso8601DateRef"}
      to:   {$ref: "#/$defs/Iso8601DateRef"}
    required: [from, to]

  Organization:
    type: object
    properties:
      name: {$ref: "#/$defs/TrimmedText"}
      url:  {$ref: "#/$defs/WebUrl"}
    required: [name]

  Tenure:
    $comment: A period of employment or study at an organization.
    allOf:
      - {$ref: "#/$defs/DateInterval"}
      - type: object
        properties:
          employer: {$ref: "#/$defs/Organization"}
          role:     {$ref: "#/$defs/TrimmedText"}
          location: {$ref: "#/$defs/Place"}
          items:
            type: array
            items: {type: string}
            minItems: 1
        required: [employer, role]

  Project:
    type: object
    $comment: A description of a project completed or participated in.
    properties:
      name: {$ref: "#/$defs/TrimmedText"}
      description: {$ref: "#/$defs/Description"}
      technology: 
        $comment: technology used in this project
        type: array          
        items: {$ref: "#/$defs/TrimmedText"}

  Employment:
    $comment: A job or contract engagement.
    allOf:
      - {$ref: "#/$defs/Tenure"}
      - type: object
        properties:
          projects: {type: array, items: { $ref: "#/$defs/Project"}}

  Education:
    $comment: A degree or formal academic program.
    allOf:
      - {$ref: "#/$defs/Tenure"}

  SkillCategory:
    $comment: A broad category of skills, top level.
    type: object
    properties:
      title: {$ref: "#/$defs/TrimmedText"}
      items: {type: array, items: {$ref: "#/$defs/SkillSet"}}
    required: [title, items]

  SkillSet:
    $comment: >
      A named category of skills. Each item is a plain skill name (string),
      an annotated skill {title, comment} (no `items`), or a nested SkillSet.
      The distinction between a leaf object and a nested group is the presence of `items`.
    type: object
    properties:
      title: {$ref: "#/$defs/TrimmedText"}
      items:
        type: array
        items:
          anyOf:
            - type: string
            - {$ref: "#/$defs/Skill"}            
    required: [title, items]

  Skill:
    $comment: A named skill with an optional explanatory comment, no sub-items.
    type: object
    properties:
      title:   {$ref: "#/$defs/TrimmedText"}
      comment: {$ref: "#/$defs/TrimmedText"}
    required: [title]
    additionalProperties: false


  Person:
    $comment: Personal and contact information of the resume owner.
    type: object
    properties:
      name:     {$ref: "#/$defs/TrimmedText"}
      title:    {$ref: "#/$defs/TrimmedText"}
      summary:  {$ref: "#/$defs/Description"}
      location: {$ref: "#/$defs/Place"}
      website:  {$ref: "#/$defs/WebUrl"}
      email:
        type: string
        format: email
      phone:    {$ref: "#/$defs/TrimmedText"}
      linkedin: {$ref: "#/$defs/WebUrl"}
    required: [name]

  Availability:
    $comment: Describes employment availability for a person.
    type: object
    properties:
      contract: 
        $comment: The person is available for short- and mid-term contracts, up to 6 months.
        type: boolean
      permanent:
        $comment: The person is available for full time positions, actively seeking.
        type: boolean
