{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://flynnstudios.dev/catalog.schema.json",
  "title": "Flynn Studios public catalog",
  "description": "Public projection of the WIM approved slice (flynn.store_catalog_public.v0, schema_version 0.1). A product appears only when Warehouse Inventory Manager has placed it in the approved handoff. Prices, package hashes, manifest paths, Drive ids, Stripe ids, R2 keys, and internal provenance are not part of this document. sales_enabled and checkout_enabled remain false until Brendan approves a later schema change.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_id",
    "schema_version",
    "site",
    "pairing_label",
    "sales_enabled",
    "checkout_enabled",
    "products"
  ],
  "properties": {
    "schema_id": {
      "const": "flynn.store_catalog_public.v0"
    },
    "schema_version": {
      "const": "0.1"
    },
    "site": {
      "const": "https://flynnstudios.dev"
    },
    "pairing_label": {
      "const": "Goes well with"
    },
    "sales_enabled": {
      "const": false
    },
    "checkout_enabled": {
      "const": false
    },
    "products": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/product"
      }
    }
  },
  "$defs": {
    "product": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "slug",
        "title",
        "short_description",
        "availability",
        "version",
        "pairs_with"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "slug": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "title": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200
        },
        "short_description": {
          "type": "string",
          "minLength": 1,
          "maxLength": 500
        },
        "availability": {
          "enum": ["available_soon", "for_sale"]
        },
        "compatibility": {
          "type": "object",
          "additionalProperties": false,
          "required": ["engine", "platform"],
          "properties": {
            "engine": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              }
            },
            "platform": {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              }
            }
          }
        },
        "version": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64
        },
        "licensing": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "ref": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            },
            "key": {
              "type": "string",
              "minLength": 1,
              "maxLength": 160
            }
          }
        },
        "pairs_with": {
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        },
        "updated_at": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80,
          "description": "Copied from the WIM handoff. The contract timezone is America/Chicago."
        },
        "card_images": {
          "type": "array",
          "minItems": 1,
          "maxItems": 12,
          "uniqueItems": true,
          "description": "Optional site-relative example images for the public card. The first path is the primary image. Prefer this over card_image when a product has more than one visual. A path is a file in Assets/product-cards/ or one product folder under it (Assets/product-cards/<id>/01.jpg). Omit until a resized visual is on the site.",
          "items": {
            "$ref": "#/$defs/cardPath"
          }
        },
        "card_image": {
          "$ref": "#/$defs/cardPath",
          "description": "Optional single site-relative example image. card_images is the primary field when more than one visual exists."
        }
      }
    },
    "cardPath": {
      "type": "string",
      "minLength": 1,
      "maxLength": 240,
      "pattern": "^Assets/product-cards/[A-Za-z0-9][A-Za-z0-9._-]*(?:/[A-Za-z0-9][A-Za-z0-9._-]*)?\\.(jpe?g|png|webp)$"
    }
  }
}
