{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://dills122.github.io/footy-data-kit/schemas/club-metadata.schema.json", "title": "ClubMetadataExport", "description": "Sidecar club identity metadata keyed by clubId. Records combine source-backed history with generated observations from the season tables.", "type": "object", "required": ["clubs"], "additionalProperties": false, "properties": { "metadata": { "$ref": "#/definitions/DatasetMetadata" }, "clubs": { "$ref": "#/definitions/ClubsMap" } }, "definitions": { "DatasetMetadata": { "type": "object", "description": "Build provenance for the generated club metadata sidecar.", "additionalProperties": false, "properties": { "schemaVersion": { "type": "integer" }, "generator": { "type": ["string", "null"] }, "generatedAt": { "type": ["string", "null"], "format": "date-time" }, "gitSha": { "type": ["string", "null"] }, "sourceFiles": { "$ref": "#/definitions/StringList" }, "buildOptions": { "type": "object", "additionalProperties": { "type": ["string", "number", "boolean", "null"] } } } }, "ClubsMap": { "type": "object", "description": "Map of canonical club key to club metadata record.", "patternProperties": { "^[a-z0-9][a-z0-9 -]*$": { "$ref": "#/definitions/ClubMetadata" } }, "additionalProperties": false }, "ClubMetadata": { "type": "object", "description": "Metadata for a single club identity.", "required": ["canonicalName"], "additionalProperties": false, "properties": { "clubId": { "type": "string", "description": "URL-safe stable club identity slug." }, "canonicalName": { "type": "string", "description": "Preferred display name for this club identity." }, "status": { "$ref": "#/definitions/ClubStatus" }, "history": { "$ref": "#/definitions/ClubHistory" }, "derived": { "$ref": "#/definitions/ClubDerivedMetadata" }, "assets": { "$ref": "#/definitions/MetadataAssets" }, "founded": { "type": ["string", "null"] }, "dissolved": { "type": ["string", "null"] }, "nameHistory": { "type": "array", "description": "Legacy name-history field. Prefer history.nameHistory for new consumers.", "items": { "$ref": "#/definitions/ClubNamePeriod" } }, "financialEvents": { "type": "array", "description": "Legacy financial-event field. Prefer source-backed lifecycle events for new consumers.", "items": { "$ref": "#/definitions/ClubFinancialEvent" } }, "notes": { "type": ["string", "null"] }, "sourceUrl": { "type": ["string", "null"], "format": "uri" } } }, "ClubStatus": { "type": "object", "description": "Consumer-facing status summary for the club identity.", "additionalProperties": false, "properties": { "current": { "type": "string", "description": "Small lifecycle/status label such as active, historical, defunct, merged, relocated, renamed, phoenix, or unknown. Use status.reason for coverage context such as below-tracked-coverage." }, "trackedFromSeason": { "type": ["integer", "null"] }, "trackedToSeason": { "type": ["integer", "null"] }, "hasUnexplainedGaps": { "type": "boolean", "description": "True only when expected tracked membership has unexplained internal absences; ordinary gaps between observed stints are represented separately in derived.coverageGaps." }, "reason": { "type": ["string", "null"] }, "reasonLabel": { "type": ["string", "null"] }, "sourceRefs": { "$ref": "#/definitions/SourceRefs" } } }, "ClubHistory": { "type": "object", "description": "Source-backed club history and expected membership context.", "additionalProperties": false, "properties": { "nameHistory": { "type": "array", "items": { "$ref": "#/definitions/ClubNamePeriod" } }, "lifecycleEvents": { "type": "array", "items": { "$ref": "#/definitions/ClubLifecycleEvent" } }, "trackedMembership": { "type": "array", "items": { "$ref": "#/definitions/ClubTrackedMembership" } }, "absenceExplanations": { "type": "array", "items": { "$ref": "#/definitions/ClubAbsenceExplanation" } } } }, "ClubDerivedMetadata": { "type": "object", "description": "Generated observations from the season table data. These fields describe dataset coverage, not necessarily real-world club activity.", "additionalProperties": false, "properties": { "source": { "type": ["string", "null"] }, "aliases": { "$ref": "#/definitions/StringList" }, "identitySources": { "type": "array", "items": { "$ref": "#/definitions/ClubIdentitySource" } }, "relationships": { "type": "array", "items": { "$ref": "#/definitions/ClubRelationship" } }, "observedNames": { "type": "array", "items": { "$ref": "#/definitions/ClubObservedName" } }, "observedNamePeriods": { "type": "array", "items": { "$ref": "#/definitions/ClubObservedNamePeriod" } }, "firstSeenSeason": { "type": ["integer", "null"] }, "lastSeenSeason": { "type": ["integer", "null"] }, "seasonsSeen": { "$ref": "#/definitions/IntegerList" }, "totalSeasonsSeen": { "type": "integer" }, "tiersSeen": { "$ref": "#/definitions/StringList" }, "tierSeasons": { "type": "array", "items": { "$ref": "#/definitions/ClubTierSeasons" } }, "coverageGaps": { "type": "array", "items": { "$ref": "#/definitions/ClubCoverageGap" } } } }, "MetadataAssets": { "type": "object", "description": "Visual and media asset candidates for this metadata identity. v1 populates club crest candidates only.", "additionalProperties": { "$ref": "#/definitions/MetadataAssetBundle" }, "properties": { "crest": { "$ref": "#/definitions/MetadataAssetBundle" } } }, "MetadataAssetBundle": { "type": "object", "required": ["status"], "additionalProperties": false, "properties": { "preferred": { "type": ["string", "null"], "description": "assetId for the preferred candidate, or null when no candidate is safe to prefer." }, "status": { "type": "string", "description": "Overall bundle status such as usable, placeholder, restricted, needs-review, needs-more-research, or failed." }, "candidates": { "type": "array", "maxItems": 5, "items": { "$ref": "#/definitions/MetadataAssetCandidate" } } } }, "MetadataAssetCandidate": { "type": "object", "required": ["assetId", "kind", "status", "source"], "additionalProperties": false, "properties": { "assetId": { "type": "string" }, "kind": { "type": "string" }, "status": { "type": "string" }, "priority": { "type": ["integer", "null"], "minimum": 1 }, "source": { "type": "string" }, "sourceUrl": { "type": ["string", "null"], "format": "uri" }, "imageUrl": { "type": ["string", "null"], "format": "uri" }, "pageUrl": { "type": ["string", "null"], "format": "uri" }, "fileTitle": { "type": ["string", "null"] }, "mimeType": { "type": ["string", "null"] }, "width": { "type": ["integer", "null"], "minimum": 0 }, "height": { "type": ["integer", "null"], "minimum": 0 }, "license": { "$ref": "#/definitions/MetadataAssetLicense" }, "colors": { "type": "array", "description": "Structured color hints used by generated placeholders or asset consumers.", "items": { "$ref": "#/definitions/MetadataAssetColor" } }, "placeholder": { "type": "boolean", "description": "True when the candidate is a generated placeholder rather than an official or source-discovered asset." }, "verification": { "$ref": "#/definitions/MetadataAssetVerification" }, "notes": { "type": ["string", "null"] } } }, "MetadataAssetColor": { "type": "object", "required": ["role", "hex"], "additionalProperties": false, "properties": { "role": { "type": "string" }, "hex": { "type": "string", "pattern": "^#[0-9A-Fa-f]{6}$" } } }, "MetadataAssetLicense": { "type": "object", "additionalProperties": false, "properties": { "shortName": { "type": ["string", "null"] }, "usageTerms": { "type": ["string", "null"] }, "licenseUrl": { "type": ["string", "null"], "format": "uri" }, "copyrighted": { "type": ["boolean", "null"] }, "attribution": { "type": ["string", "null"] }, "credit": { "type": ["string", "null"] }, "artist": { "type": ["string", "null"] } } }, "MetadataAssetVerification": { "type": "object", "additionalProperties": false, "properties": { "identityMatch": { "type": ["string", "null"] }, "licenseCheck": { "type": ["string", "null"] }, "httpCheck": { "type": ["string", "null"] }, "needsManualReview": { "type": "boolean" }, "reviewReasons": { "$ref": "#/definitions/StringList" }, "checkedAt": { "type": ["string", "null"], "format": "date-time" } } }, "ClubNamePeriod": { "type": "object", "required": ["name"], "additionalProperties": false, "properties": { "name": { "type": "string" }, "startSeason": { "type": ["integer", "null"] }, "endSeason": { "type": ["integer", "null"] }, "notes": { "type": ["string", "null"] } } }, "ClubFinancialEvent": { "type": "object", "required": ["type"], "additionalProperties": false, "properties": { "type": { "type": "string" }, "startSeason": { "type": ["integer", "null"] }, "endSeason": { "type": ["integer", "null"] }, "seasonsMissed": { "$ref": "#/definitions/IntegerList" }, "notes": { "type": ["string", "null"] } } }, "ClubLifecycleEvent": { "type": "object", "required": ["type"], "additionalProperties": false, "properties": { "type": { "type": "string", "description": "Event label such as renamed, merged, dissolved, not-re-elected, relocated, or phoenix." }, "season": { "type": ["integer", "null"] }, "date": { "type": ["string", "null"] }, "fromSeason": { "type": ["integer", "null"] }, "toSeason": { "type": ["integer", "null"] }, "fromName": { "type": ["string", "null"] }, "toName": { "type": ["string", "null"] }, "label": { "type": ["string", "null"] }, "description": { "type": ["string", "null"] }, "notes": { "type": ["string", "null"] }, "sourceRefs": { "$ref": "#/definitions/SourceRefs" } } }, "ClubTrackedMembership": { "type": "object", "description": "Observed stints inside the supported season dataset, not a claim of continuous real-world club existence.", "required": ["fromSeason"], "additionalProperties": false, "properties": { "fromSeason": { "type": "integer" }, "toSeason": { "type": ["integer", "null"] }, "tiers": { "$ref": "#/definitions/StringList" }, "basis": { "type": ["string", "null"] }, "notes": { "type": ["string", "null"] }, "sourceRefs": { "$ref": "#/definitions/SourceRefs" } } }, "ClubAbsenceExplanation": { "type": "object", "required": ["fromSeason", "reason"], "additionalProperties": false, "properties": { "fromSeason": { "type": "integer" }, "toSeason": { "type": ["integer", "null"] }, "reason": { "type": "string", "description": "Broad reason code such as official-competition-paused, outside-tracked-coverage, below-tracked-coverage, club-inactive, club-dissolved, club-reformed, or unknown." }, "linkedEventType": { "type": ["string", "null"] }, "basis": { "type": ["string", "null"] }, "notes": { "type": ["string", "null"] }, "sourceRefs": { "$ref": "#/definitions/SourceRefs" } } }, "ClubIdentitySource": { "type": "object", "required": ["type", "sourceUrl"], "additionalProperties": false, "properties": { "type": { "type": "string" }, "sourceUrl": { "type": "string", "format": "uri" }, "notes": { "type": ["string", "null"] } } }, "ClubSourceRef": { "type": "object", "required": ["type", "sourceUrl"], "additionalProperties": false, "properties": { "type": { "type": "string" }, "sourceUrl": { "type": "string", "format": "uri" }, "notes": { "type": ["string", "null"] } } }, "ClubRelationship": { "type": "object", "required": ["clubKey", "relationship", "direction"], "additionalProperties": false, "properties": { "clubKey": { "type": "string" }, "relationship": { "type": "string" }, "direction": { "type": "string" }, "season": { "type": ["integer", "null"] }, "label": { "type": ["string", "null"] }, "sourceRefs": { "$ref": "#/definitions/SourceRefs" }, "notes": { "type": ["string", "null"] } } }, "ClubObservedName": { "type": "object", "required": ["rawName", "normalizedName", "firstSeenSeason", "lastSeenSeason"], "additionalProperties": false, "properties": { "rawName": { "type": "string" }, "normalizedName": { "type": "string" }, "firstSeenSeason": { "type": "integer" }, "lastSeenSeason": { "type": "integer" }, "seasonsSeen": { "$ref": "#/definitions/IntegerList" }, "tiersSeen": { "$ref": "#/definitions/StringList" } } }, "ClubObservedNamePeriod": { "type": "object", "required": ["name", "startSeason", "endSeason"], "additionalProperties": false, "properties": { "name": { "type": "string" }, "startSeason": { "type": "integer" }, "endSeason": { "type": "integer" } } }, "ClubTierSeasons": { "type": "object", "required": ["tierKey", "seasons"], "additionalProperties": false, "properties": { "tierKey": { "type": "string", "pattern": "^tier\\d+$" }, "seasons": { "$ref": "#/definitions/IntegerList" } } }, "ClubCoverageGap": { "type": "object", "required": ["startSeason", "endSeason", "length"], "additionalProperties": false, "properties": { "startSeason": { "type": "integer" }, "endSeason": { "type": "integer" }, "length": { "type": "integer" } } }, "SourceRefs": { "type": "array", "items": { "$ref": "#/definitions/ClubSourceRef" } }, "StringList": { "type": "array", "items": { "type": "string" } }, "IntegerList": { "type": "array", "items": { "type": "integer" } } } }