{
  "crubal": "2",
  "package": "service",
  "version": "2026-10-14",
  "id": "crubal.com/service",
  "owner": "crubal.com",
  "label": "Services",
  "licence": "CC-BY-4.0",
  "prefixes": {
    "schema": "https://schema.org/"
  },
  "kinds": [
    {
      "kind": "service",
      "levels": [
        "service",
        "booking"
      ]
    }
  ],
  "facets": [
    {
      "facet": "serviceName",
      "type": "text",
      "same-as": [
        "schema:name"
      ],
      "length": "200"
    },
    {
      "facet": "summary",
      "type": "text",
      "same-as": [
        "schema:description"
      ]
    },
    {
      "facet": "provider",
      "type": "text",
      "same-as": [
        "schema:provider"
      ]
    },
    {
      "facet": "area",
      "type": "text",
      "same-as": [
        "schema:areaServed"
      ]
    },
    {
      "facet": "duration",
      "type": "number",
      "unit": "min",
      "accepts": [
        "h",
        "s"
      ]
    },
    {
      "facet": "bookingStart",
      "type": "date",
      "same-as": [
        "schema:startTime"
      ],
      "precision": "minute"
    },
    {
      "facet": "bookingStatus",
      "type": "choice",
      "values": [
        {
          "value": "requested"
        },
        {
          "value": "confirmed"
        },
        {
          "value": "completed"
        },
        {
          "value": "cancelled"
        },
        {
          "value": "no-show"
        }
      ],
      "ranked": true
    },
    {
      "facet": "bookingNotes",
      "type": "text"
    },
    {
      "facet": "day",
      "type": "choice",
      "values": [
        {
          "value": "mon"
        },
        {
          "value": "tue"
        },
        {
          "value": "wed"
        },
        {
          "value": "thu"
        },
        {
          "value": "fri"
        },
        {
          "value": "sat"
        },
        {
          "value": "sun"
        }
      ],
      "fixed": true
    },
    {
      "facet": "opens",
      "type": "time",
      "precision": "minute"
    },
    {
      "facet": "closes",
      "type": "time",
      "precision": "minute"
    },
    {
      "facet": "hours",
      "type": "compound",
      "label": "Opening hours",
      "describe": "One row per opening period; a day may have several. A zone, when it matters, qualifies the times.",
      "pick": "any",
      "facets": [
        {
          "facet": "day",
          "type": "choice",
          "values": [
            {
              "value": "mon"
            },
            {
              "value": "tue"
            },
            {
              "value": "wed"
            },
            {
              "value": "thu"
            },
            {
              "value": "fri"
            },
            {
              "value": "sat"
            },
            {
              "value": "sun"
            }
          ],
          "fixed": true
        },
        {
          "facet": "opens",
          "type": "time",
          "precision": "minute"
        },
        {
          "facet": "closes",
          "type": "time",
          "precision": "minute"
        }
      ]
    }
  ],
  "classes": [
    {
      "class": "Service",
      "label": "Service",
      "for": [
        "service"
      ],
      "facets": [
        {
          "facet": "serviceName",
          "required": true
        },
        {
          "facet": "summary"
        },
        {
          "facet": "provider"
        },
        {
          "facet": "area"
        },
        {
          "facet": "duration"
        },
        {
          "facet": "hours"
        },
        {
          "facet": "bookingStart",
          "level": "booking",
          "section": "Booking"
        },
        {
          "facet": "bookingStatus",
          "level": "booking",
          "section": "Booking"
        },
        {
          "facet": "bookingNotes",
          "level": "booking",
          "section": "Booking"
        }
      ]
    }
  ],
  "rules": [
    {
      "rule": "bookingHasStart",
      "for": "booking",
      "when": "bookingStatus in confirmed, completed",
      "then": "bookingStart has",
      "strength": "must",
      "because": "a confirmed booking needs its start time"
    }
  ]
}
