{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://migrationfit.com/data/schema.json",
  "title": "MigrationFit Export Schema",
  "description": "JSON Schema for all MigrationFit static data exports. schema_version v1 (gig-migration-export-v2). See /data/export-contract-v1.md for full narrative.",
  "schema_contract_version": "1",
  "generated_at": "2026-06-12",
  "site_version": "A02",
  "$defs": {
    "envelope": {
      "type": "object",
      "description": "Fields present in every export envelope.",
      "required": ["schema_version", "data_version", "generated_at"],
      "properties": {
        "schema_version": {
          "type": "string",
          "const": "gig-migration-export-v2",
          "description": "Stable schema-version tag. Increment only on breaking changes."
        },
        "data_version": {
          "type": "string",
          "description": "Content stamp — ISO date of most recent data update or release label."
        },
        "generated_at": {
          "type": "string",
          "description": "ISO date or datetime when this file was generated by the build."
        }
      }
    },
    "entity_id": {
      "type": "string",
      "pattern": "^[a-z]{2}\\.[a-z0-9\\-]+$",
      "description": "Stable entity identifier in the form {cc}.{slug}, e.g. de.pirna. Never changes once published; renames add an alias entry."
    },
    "source_id": {
      "type": "string",
      "pattern": "^[a-z0-9_]+$",
      "description": "Stable source registry key matching sample-source-registry.json or sources.sample.json."
    },
    "citation_atom": {
      "type": "object",
      "description": "Full provenance object embedded in every published metric value.",
      "required": [
        "metric_id",
        "entity_id",
        "value",
        "unit",
        "date_observed",
        "last_checked",
        "source_id",
        "source_grade",
        "confidence",
        "fallback_level",
        "citation_text"
      ],
      "properties": {
        "metric_id": { "type": "string" },
        "entity_id": { "$ref": "#/$defs/entity_id" },
        "value": { "description": "Measured value." },
        "unit": { "type": ["string", "null"] },
        "date_observed": { "type": ["string", "null"], "format": "date" },
        "last_checked": { "type": ["string", "null"] },
        "source_id": { "$ref": "#/$defs/source_id" },
        "source_grade": { "type": ["string", "null"], "enum": ["A", "B", "C", "D", null] },
        "confidence": { "type": "string", "enum": ["A", "B", "C", "D"] },
        "fallback_level": {
          "type": "string",
          "enum": ["city", "region", "country_level_estimate", "no_data"]
        },
        "methodology_id": {
          "type": ["string", "null"],
          "description": "Optional methodology registry key (see export-contract-v1.md §5)."
        },
        "citation_text": {
          "type": "string",
          "description": "Self-sufficient one-line citation: 'Source: {name} ({date}), confidence {grade}, via MigrationFit.'"
        }
      }
    },
    "metric_value_export": {
      "allOf": [
        { "$ref": "#/$defs/citation_atom" },
        {
          "type": "object",
          "properties": {
            "metric_name": { "type": ["string", "null"] },
            "metric_description": { "type": ["string", "null"] },
            "domain": { "type": ["string", "null"] },
            "value_type": { "type": ["string", "null"] },
            "value_display": { "type": ["string", "null"] },
            "source_name": { "type": ["string", "null"] },
            "source_url": { "type": ["string", "null"] },
            "source_type": { "type": ["string", "null"] },
            "fallback_level": { "type": "string" },
            "data_level": { "type": ["string", "null"] },
            "data_level_label": { "type": ["string", "null"] },
            "trend": { "$ref": "#/$defs/metric_trend" }
          }
        }
      ]
    },
    "metric_trend": {
      "type": ["object", "null"],
      "properties": {
        "period": { "type": ["string", "null"], "enum": ["yoy", "since_first_observation", null] },
        "direction": { "type": "string", "enum": ["up", "down", "flat"] },
        "from_date": { "type": ["string", "null"], "format": "date" },
        "current_date": { "type": ["string", "null"], "format": "date" },
        "previous_date": { "type": ["string", "null"], "format": "date" },
        "current_value": { "type": ["number", "null"] },
        "previous_value": { "type": ["number", "null"] },
        "delta": { "type": ["number", "null"] },
        "delta_pct": { "type": ["number", "null"] },
        "source_id": { "type": ["string", "null"] },
        "significant": { "type": ["boolean", "null"] }
      }
    },
    "metric_timeseries_observation": {
      "type": "object",
      "required": ["date", "value"],
      "properties": {
        "date": { "type": "string", "format": "date" },
        "value": { "type": "number" },
        "unit": { "type": ["string", "null"] },
        "source_id": { "type": ["string", "null"] },
        "source_url": { "type": ["string", "null"] },
        "confidence": { "type": ["string", "null"] },
        "fallback_level": { "type": ["string", "null"] }
      }
    },
    "cost_snapshot": {
      "type": "object",
      "description": "Derived monthly budget estimate for household profiles. v1 includes rent, public transport, statutory health insurance estimate and child benefit offset; v2 (data pack A, task 85) adds groceries, utilities, income tax / social contribution offsets and net-of-average-salary per profile, surfacing the net disposable income position.",
      "required": ["status", "methodology_id", "currency", "profiles"],
      "properties": {
        "status": { "type": "string", "enum": ["available", "partial", "insufficient_data"] },
        "methodology_id": { "type": "string", "enum": ["cost_snapshot_v1", "cost_snapshot_v2"] },
        "previous_methodology_id": { "type": "string", "enum": ["cost_snapshot_v1", "cost_snapshot_v2", null] },
        "currency": { "type": "string", "const": "EUR" },
        "caveat": { "type": "string" },
        "methodology_url": { "type": "string" },
        "methodology_v1_url": { "type": "string" },
        "missing_components": { "type": "array", "items": { "type": "string" } },
        "snapshot_v1": {
          "type": ["object", "null"],
          "description": "v1 snapshot embedded for backward compatibility (v2 only).",
          "properties": {
            "status": { "type": "string", "enum": ["available", "insufficient_data"] },
            "methodology_id": { "type": "string", "const": "cost_snapshot_v1" },
            "currency": { "type": "string", "const": "EUR" },
            "caveat": { "type": "string" },
            "methodology_url": { "type": "string" },
            "missing_components": { "type": "array", "items": { "type": "string" } },
            "profiles": { "$ref": "#/$defs/cost_snapshot_v1_profiles" }
          }
        },
        "profiles": {
          "type": "object",
          "properties": {
            "single": { "$ref": "#/$defs/cost_snapshot_v2_profile" },
            "couple": { "$ref": "#/$defs/cost_snapshot_v2_profile" },
            "family": { "$ref": "#/$defs/cost_snapshot_v2_profile" }
          }
        }
      }
    },
    "cost_snapshot_v1_profiles": {
      "type": "object",
      "properties": {
        "single": { "$ref": "#/$defs/cost_snapshot_profile" },
        "couple": { "$ref": "#/$defs/cost_snapshot_profile" },
        "family": { "$ref": "#/$defs/cost_snapshot_profile" }
      }
    },
    "cost_snapshot_v2_profile": {
      "allOf": [
        { "$ref": "#/$defs/cost_snapshot_profile" },
        {
          "type": "object",
          "properties": {
            "v1_total_eur_month": { "type": ["number", "null"] },
            "v1_components": {
              "type": "array",
              "items": {
                "type": "object",
                "required": ["id", "label", "value_eur_month"],
                "properties": {
                  "id": { "type": "string" },
                  "label": { "type": "string" },
                  "value_eur_month": { "type": ["number", "null"] },
                  "metric_id": { "type": ["string", "null"] },
                  "source": { "type": ["object", "null"] }
                }
              }
            },
            "v1_missing_components": { "type": "array", "items": { "type": "string" } },
            "groceries_eur_month": { "type": ["number", "null"] },
            "utilities_eur_month": { "type": ["number", "null"] },
            "net_income_eur_month": { "type": ["number", "null"] },
            "income_tax_offset_eur_month": { "type": ["number", "null"] },
            "social_contrib_offset_eur_month": { "type": ["number", "null"] },
            "total_expenses_eur_month": { "type": ["number", "null"] },
            "budget_vs_typical_net_ratio": { "type": ["number", "null"] },
            "net_position": { "type": ["string", "null"], "enum": ["surplus", "shortfall", null] }
          }
        }
      ]
    },
    "cost_snapshot_profile": {
      "type": "object",
      "required": ["label", "total_eur_month", "components"],
      "properties": {
        "label": { "type": "string" },
        "total_eur_month": { "type": ["number", "null"] },
        "total_display": { "type": ["string", "null"] },
        "components": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["id", "label", "value_eur_month"],
            "properties": {
              "id": { "type": "string" },
              "label": { "type": "string" },
              "value_eur_month": { "type": ["number", "null"] },
              "metric_id": { "type": ["string", "null"] },
              "source": { "type": ["object", "null"] }
            }
          }
        },
        "missing_components": { "type": "array", "items": { "type": "string" } }
      }
    },
    "city_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug", "name", "entity_id", "metric_values"],
          "properties": {
            "type": { "const": "City" },
            "slug": { "type": "string" },
            "name": { "type": "string" },
            "entity_id": { "$ref": "#/$defs/entity_id" },
            "country": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "metric_values": {
              "type": "array",
              "items": { "$ref": "#/$defs/metric_value_export" }
            },
            "cost_snapshot": { "$ref": "#/$defs/cost_snapshot" }
          }
        }
      ]
    },
    "country_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug", "name", "entity_id", "metric_values"],
          "properties": {
            "type": { "const": "Country" },
            "slug": { "type": "string" },
            "name": { "type": "string" },
            "entity_id": { "$ref": "#/$defs/entity_id" },
            "html_url": { "type": "string", "format": "uri" },
            "metric_values": {
              "type": "array",
              "items": { "$ref": "#/$defs/metric_value_export" }
            }
          }
        }
      ]
    },
    "region_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug", "name", "entity_id"],
          "properties": {
            "type": { "const": "Region" },
            "slug": { "type": "string" },
            "name": { "type": "string" },
            "entity_id": { "$ref": "#/$defs/entity_id" },
            "html_url": { "type": "string", "format": "uri" },
            "metric_values": {
              "type": "array",
              "items": { "$ref": "#/$defs/metric_value_export" }
            }
          }
        }
      ]
    },
    "metric_timeseries_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "metric_id", "canonical_metric_id", "entity_id", "entity_type", "observations"],
          "properties": {
            "type": { "const": "MetricTimeSeries" },
            "metric_id": { "type": "string" },
            "canonical_metric_id": { "type": "string" },
            "metric_name": { "type": ["string", "null"] },
            "domain": { "type": ["string", "null"] },
            "unit": { "type": ["string", "null"] },
            "entity_type": { "type": "string", "enum": ["city", "country", "region"] },
            "entity_slug": { "type": "string" },
            "entity_id": { "$ref": "#/$defs/entity_id" },
            "country_code": { "type": ["string", "null"], "pattern": "^[a-z]{2}$" },
            "html_url": { "type": ["string", "null"], "format": "uri" },
            "updated": { "type": ["string", "null"] },
            "trend": { "$ref": "#/$defs/metric_trend" },
            "observations": {
              "type": "array",
              "items": { "$ref": "#/$defs/metric_timeseries_observation" }
            }
          }
        }
      ]
    },
    "compare_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug"],
          "properties": {
            "type": { "const": "CityCompare" },
            "slug": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" }
          }
        }
      ]
    },
    "selection_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug"],
          "properties": {
            "type": { "const": "CitySelection" },
            "slug": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" }
          }
        }
      ]
    },
    "question_driven_report_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "slug", "question", "rows"],
          "properties": {
            "type": { "const": "QuestionDrivenReport" },
            "slug": { "type": "string" },
            "question": { "type": "string" },
            "scope": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "pdf_url": { "type": ["string", "null"], "format": "uri" },
            "rows": { "type": "array" }
          }
        }
      ]
    },
    "question_driven_report_catalog_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "items"],
          "properties": {
            "type": { "const": "QuestionDrivenReportCatalog" },
            "items": { "type": "array" }
          }
        }
      ]
    },
    "profile_ranking_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "profile_slug", "country_code", "title", "indexable", "weights", "coverage", "rows"],
          "properties": {
            "type": { "const": "CountryProfileRanking" },
            "profile_slug": { "type": "string" },
            "profile_name": { "type": "string" },
            "scoring_profile_id": { "type": "string" },
            "country_code": { "type": "string", "pattern": "^[a-z]{2}$" },
            "country_slug": { "type": "string" },
            "country_name": { "type": "string" },
            "title": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "advisor_url": { "type": "string" },
            "visas_url": { "type": "string" },
            "indexable": { "type": "boolean" },
            "gateShare": { "type": "number" },
            "gateCoveredSubindexes": { "type": "integer" },
            "gateRequiredSubindexes": { "type": "integer" },
            "weights": { "type": "object" },
            "coverage": { "type": "array" },
            "row_count": { "type": "integer" },
            "total_ranked_rows": { "type": "integer" },
            "truncated": { "type": "boolean" },
            "relevant_routes": { "type": "array" },
            "profession_recognition": { "type": ["object", "null"] },
            "related_selections": { "type": "array" },
            "rows": { "type": "array" }
          }
        }
      ]
    },
    "corridor_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "origin_id", "destination_code", "title", "passport_rule", "legal_routes", "timeline", "best_cities"],
          "properties": {
            "type": { "const": "MigrationCorridor" },
            "origin_id": { "type": "string" },
            "origin_name": { "type": "string" },
            "origin_slug": { "type": "string" },
            "destination_code": { "type": "string", "pattern": "^[a-z]{2}$" },
            "destination_name": { "type": "string" },
            "destination_slug": { "type": "string" },
            "title": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "advisor_url": { "type": "string" },
            "indexable": { "type": "boolean" },
            "data_backed_section_count": { "type": "integer" },
            "section_coverage": { "type": "array" },
            "passport_rule": { "type": "object" },
            "legal_routes": { "type": "array" },
            "timeline": { "type": "string" },
            "best_cities": { "type": "array" },
            "recognition": { "type": ["object", "null"] },
            "sources": { "type": "array" }
          }
        }
      ]
    },
    "tax_rule_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "country_code", "year", "rules"],
          "properties": {
            "type": { "const": "TaxRuleSet" },
            "country_code": { "type": "string", "pattern": "^[a-z]{2}$" },
            "country_name": { "type": "string" },
            "year": { "type": "integer" },
            "title": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "verify_url": { "type": "string", "format": "uri" },
            "disclaimer": { "type": "string" },
            "supported_cases": { "type": "array", "items": { "type": "string" } },
            "unsupported_cases": { "type": "array", "items": { "type": "string" } },
            "default_inputs": { "type": "object" },
            "published_profiles": { "type": "object" },
            "default_result": { "type": "object" },
            "rules": { "type": "object" }
          }
        }
      ]
    },
    "move_cost_rule_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "country_code", "country_name", "route_options", "profile_templates"],
          "properties": {
            "type": { "const": "MoveCostRuleSet" },
            "country_code": { "type": "string", "pattern": "^[a-z]{2}$" },
            "country_name": { "type": "string" },
            "country_slug": { "type": ["string", "null"] },
            "city_count": { "type": "integer" },
            "tool_url": { "type": "string", "format": "uri" },
            "json_url": { "type": "string", "format": "uri" },
            "route_options": { "type": "array" },
            "profile_templates": { "type": "object" }
          }
        }
      ]
    },
    "catalog_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["catalog"],
          "properties": {
            "catalog": { "type": "object" }
          }
        }
      ]
    },
    "legal_catalog_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "items"],
          "properties": {
            "type": { "const": "LegalCatalog" },
            "html_url": { "type": "string", "format": "uri" },
            "items": { "type": "array" }
          }
        }
      ]
    },
    "legal_passport_export": {
      "allOf": [
        { "$ref": "#/$defs/envelope" },
        {
          "type": "object",
          "required": ["type", "passport_id", "rules"],
          "properties": {
            "type": { "const": "LegalPassport" },
            "passport_id": { "type": "string" },
            "passport_name": { "type": "string" },
            "rule_count": { "type": "integer" },
            "indexability": { "type": "string" },
            "html_url": { "type": "string", "format": "uri" },
            "rules": { "type": "array" }
          }
        }
      ]
    },
    "error_body": {
      "type": "object",
      "required": ["error", "schema_version", "hint", "catalog_url"],
      "properties": {
        "error": { "type": "string", "const": "not_found" },
        "schema_version": { "type": "string", "const": "gig-migration-export-v2" },
        "hint": { "type": "string" },
        "catalog_url": { "type": "string", "format": "uri" }
      }
    }
  },
  "export_types": {
    "city": { "$ref": "#/$defs/city_export" },
    "country": { "$ref": "#/$defs/country_export" },
    "region": { "$ref": "#/$defs/region_export" },
    "metric_timeseries": { "$ref": "#/$defs/metric_timeseries_export" },
    "compare": { "$ref": "#/$defs/compare_export" },
    "selection": { "$ref": "#/$defs/selection_export" },
    "question_driven_report": { "$ref": "#/$defs/question_driven_report_export" },
    "question_driven_report_catalog": { "$ref": "#/$defs/question_driven_report_catalog_export" },
    "profile_ranking": { "$ref": "#/$defs/profile_ranking_export" },
    "corridor": { "$ref": "#/$defs/corridor_export" },
    "tax_rule": { "$ref": "#/$defs/tax_rule_export" },
    "move_cost_rule": { "$ref": "#/$defs/move_cost_rule_export" },
    "legal_catalog": { "$ref": "#/$defs/legal_catalog_export" },
    "legal_passport": { "$ref": "#/$defs/legal_passport_export" },
    "catalog": { "$ref": "#/$defs/catalog_export" },
    "error": { "$ref": "#/$defs/error_body" }
  },
  "exports": {
    "catalog": "/data/catalog.json",
    "schema": "/data/schema.json",
    "error_body": "/data/404.json",
    "openapi": "/openapi.yaml",
    "ai_plugin": "/.well-known/ai-plugin.json",
    "countries": "/data/countries/{cc}.json",
    "legal_catalog": "/data/legal/catalog.json",
    "legal_passport": "/data/legal/passport/{cc}.json",
    "countries_legacy": "/data/countries/{slug}.json",
    "country_topics": "/data/countries/{cc}/{topic}.json",
    "cities": "/data/cities/{cc}/{slug}.json",
    "cities_legacy": "/data/cities/{slug}.json",
    "timeseries": "/data/timeseries/{metric_id}/{entity_id}.json",
    "compare": "/data/compare/{city-a}-vs-{city-b}.json",
    "selections": "/data/selections/{slug}.json",
    "reports_catalog": "/data/reports/catalog.json",
    "reports": "/data/reports/{slug}.json",
    "reports_csv": "/data/reports/{slug}.csv",
    "profiles": "/data/profiles/{profile}/{cc}.json",
    "routes": "/data/routes/{from}-{to}.json",
    "tax_rules": "/data/tax-rules/{cc}-{year}.json",
    "move_cost_rules": "/data/move-cost-rules/{cc}.json",
    "regions": "/data/regions/{cc}/{slug}.json",
    "metrics": "/data/metrics/{metric_id}.json",
    "bulk_manifest": "/data/bulk/manifest.json",
    "bulk_country": "/data/bulk/{cc}.json.gz",
    "cities_csv": "/data/csv/cities.csv"
  }
}
