{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/haya-inc/civic-contribution-catalog/blob/main/schema/catalog.schema.json",
  "title": "Civic Contribution Catalog",
  "description": "日本に関係する、市民が参加可能な公益的貢献機会のカタログ。",
  "type": "object",
  "additionalProperties": false,
  "required": ["schema_version", "updated_at", "language", "scope", "organizations", "records"],
  "properties": {
    "$schema": {
      "type": "string"
    },
    "schema_version": {
      "const": "1.0.0"
    },
    "updated_at": {
      "$ref": "#/$defs/date"
    },
    "language": {
      "const": "ja"
    },
    "scope": {
      "type": "string",
      "minLength": 1
    },
    "organizations": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/organization"
      }
    },
    "records": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/record"
      }
    }
  },
  "$defs": {
    "date": {
      "type": "string",
      "format": "date"
    },
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
    },
    "url": {
      "type": "string",
      "format": "uri",
      "pattern": "^https://"
    },
    "nonEmptyStringArray": {
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 1
      }
    },
    "organization": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "name", "kind", "jurisdiction", "area", "url"],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "kind": {
          "enum": [
            "national_government",
            "local_government",
            "independent_administrative_agency",
            "public_interest_organization",
            "academic_consortium",
            "nonprofit",
            "civic_community",
            "international_community",
            "other"
          ]
        },
        "jurisdiction": {
          "enum": ["national", "local", "multi_local", "global"]
        },
        "area": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "description": "ISO 3166-1/2を基本とし、全世界はGLOBALを使う。"
          }
        },
        "url": {
          "$ref": "#/$defs/url"
        }
      }
    },
    "participation": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "online_level",
        "area",
        "languages",
        "account_required",
        "cost",
        "commitment",
        "steps"
      ],
      "properties": {
        "online_level": {
          "enum": ["fully_online", "online_with_local_action", "online_application_only", "varies"]
        },
        "area": {
          "$ref": "#/$defs/nonEmptyStringArray"
        },
        "languages": {
          "$ref": "#/$defs/nonEmptyStringArray"
        },
        "account_required": {
          "enum": ["yes", "no", "varies", "unknown"]
        },
        "cost": {
          "enum": ["free", "may_apply", "varies", "unknown"]
        },
        "commitment": {
          "type": "string",
          "minLength": 1
        },
        "steps": {
          "$ref": "#/$defs/nonEmptyStringArray"
        }
      }
    },
    "eligibility": {
      "type": "object",
      "additionalProperties": false,
      "required": ["summary", "age", "residency", "skills"],
      "properties": {
        "summary": {
          "type": "string",
          "minLength": 1
        },
        "age": {
          "type": "string",
          "minLength": 1
        },
        "residency": {
          "type": "string",
          "minLength": 1
        },
        "skills": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string",
            "minLength": 1
          }
        }
      }
    },
    "links": {
      "type": "object",
      "additionalProperties": false,
      "required": ["website", "participate"],
      "properties": {
        "website": {
          "$ref": "#/$defs/url"
        },
        "participate": {
          "$ref": "#/$defs/url"
        },
        "search": {
          "$ref": "#/$defs/url"
        },
        "terms": {
          "$ref": "#/$defs/url"
        },
        "feed": {
          "$ref": "#/$defs/url"
        }
      }
    },
    "agent": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "discovery_method",
        "discovery_url",
        "submission_method",
        "automation_policy",
        "ai_assistance",
        "safe_support",
        "human_only_actions",
        "notes"
      ],
      "properties": {
        "discovery_method": {
          "enum": ["rss", "structured_page", "html_search", "github_api", "manual"]
        },
        "discovery_url": {
          "$ref": "#/$defs/url"
        },
        "submission_method": {
          "enum": [
            "web_form",
            "external_site",
            "github_issue",
            "account_editor",
            "community_signup",
            "varies"
          ]
        },
        "automation_policy": {
          "enum": ["human_action_required", "terms_review_required", "unknown"]
        },
        "ai_assistance": {
          "enum": ["high", "medium", "low"]
        },
        "safe_support": {
          "$ref": "#/$defs/nonEmptyStringArray"
        },
        "human_only_actions": {
          "$ref": "#/$defs/nonEmptyStringArray"
        },
        "notes": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "freshness": {
      "type": "object",
      "additionalProperties": false,
      "required": ["last_verified", "review_after", "confidence", "status_basis"],
      "properties": {
        "last_verified": {
          "$ref": "#/$defs/date"
        },
        "review_after": {
          "$ref": "#/$defs/date"
        },
        "confidence": {
          "enum": ["high", "medium", "low"]
        },
        "status_basis": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "evidence": {
      "type": "object",
      "additionalProperties": false,
      "required": ["url", "title", "publisher", "source_kind", "checked_at", "supports", "note"],
      "properties": {
        "url": {
          "$ref": "#/$defs/url"
        },
        "title": {
          "type": "string",
          "minLength": 1
        },
        "publisher": {
          "type": "string",
          "minLength": 1
        },
        "source_kind": {
          "enum": ["official", "official_repository", "official_terms"]
        },
        "checked_at": {
          "$ref": "#/$defs/date"
        },
        "supports": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "enum": [
              "provider",
              "status",
              "participation",
              "eligibility",
              "application",
              "automation_policy"
            ]
          }
        },
        "note": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "record": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "record_type",
        "organization_ids",
        "name",
        "summary",
        "status",
        "topics",
        "contribution_modes",
        "participation",
        "eligibility",
        "links",
        "agent",
        "freshness",
        "evidence",
        "cautions",
        "tags"
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/id"
        },
        "record_type": {
          "enum": ["directory", "service", "opportunity"]
        },
        "organization_ids": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "$ref": "#/$defs/id"
          }
        },
        "name": {
          "type": "string",
          "minLength": 1
        },
        "summary": {
          "type": "string",
          "minLength": 1
        },
        "status": {
          "enum": ["open", "recurring", "paused", "closed", "unknown"]
        },
        "topics": {
          "$ref": "#/$defs/nonEmptyStringArray"
        },
        "contribution_modes": {
          "type": "array",
          "minItems": 1,
          "uniqueItems": true,
          "items": {
            "enum": [
              "policy_feedback",
              "general_volunteering",
              "professional_skills",
              "civic_tech",
              "software_feedback",
              "transcription",
              "mapping",
              "field_report",
              "citizen_science",
              "translation",
              "research",
              "event_support",
              "community_support",
              "other"
            ]
          }
        },
        "participation": {
          "$ref": "#/$defs/participation"
        },
        "eligibility": {
          "$ref": "#/$defs/eligibility"
        },
        "links": {
          "$ref": "#/$defs/links"
        },
        "agent": {
          "$ref": "#/$defs/agent"
        },
        "freshness": {
          "$ref": "#/$defs/freshness"
        },
        "evidence": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/evidence"
          }
        },
        "cautions": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string",
            "minLength": 1
          }
        },
        "tags": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string",
            "minLength": 1
          }
        },
        "schedule": {
          "type": "object",
          "additionalProperties": false,
          "required": ["starts_at", "deadline_at", "timezone", "recurrence"],
          "properties": {
            "starts_at": {
              "type": ["string", "null"],
              "format": "date-time"
            },
            "deadline_at": {
              "type": ["string", "null"],
              "format": "date-time"
            },
            "timezone": {
              "type": "string",
              "minLength": 1
            },
            "recurrence": {
              "type": "string",
              "minLength": 1
            }
          }
        }
      }
    }
  }
}
