{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "urn:zendo:frontend-workspace:v1",
  "title": "Zendo frontend domain records",
  "description": "Additive v1 records. Relationships, cross-field dates, command authorization and migration are defined in docs/ontology.md and enforced by the service. This schema describes persisted/snapshot records, not mutation payloads.",
  "type": "object",
  "required": [
    "guestProfile",
    "brief",
    "context",
    "captureSettings"
  ],
  "properties": {
    "guestProfile": {
      "$ref": "#/$defs/GuestProfile"
    },
    "brief": {
      "$ref": "#/$defs/TripBrief"
    },
    "captureSettings": {
      "$ref": "#/$defs/CaptureSettings"
    },
    "context": {
      "type": "object",
      "required": [
        "schema",
        "guestId",
        "preferences",
        "referencePoints"
      ],
      "properties": {
        "schema": {
          "const": "zendo.guest-context/v1"
        },
        "guestId": {
          "type": "string",
          "maxLength": 120
        },
        "preferences": {
          "type": "string",
          "maxLength": 4000
        },
        "referencePoints": {
          "type": "array",
          "maxItems": 100,
          "items": {
            "$ref": "#/$defs/ContextReference"
          }
        }
      },
      "additionalProperties": true
    },
    "guest": {
      "$ref": "#/$defs/Guest"
    },
    "recommendations": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Recommendation"
      }
    },
    "selection": {
      "anyOf": [
        {
          "$ref": "#/$defs/Selection"
        },
        {
          "type": "null"
        }
      ]
    },
    "planningSession": {
      "anyOf": [
        {
          "$ref": "#/$defs/PlanningSession"
        },
        {
          "type": "null"
        }
      ]
    },
    "planningSessions": {
      "type": "array",
      "maxItems": 50,
      "items": {
        "$ref": "#/$defs/PlanningSession"
      }
    }
  },
  "additionalProperties": true,
  "$defs": {
    "GuestProfile": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.guest-profile/v1"
        },
        "id": {
          "type": "string",
          "maxLength": 120
        },
        "revision": {
          "type": "integer",
          "minimum": 1
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "company": {
          "type": "string",
          "maxLength": 100
        },
        "notes": {
          "type": "string",
          "maxLength": 2000
        },
        "preferences": {
          "type": "string",
          "maxLength": 4000
        },
        "profileId": {
          "type": "string"
        },
        "guestId": {
          "type": "string"
        },
        "chunks": {
          "type": "array",
          "maxItems": 7,
          "items": {
            "$ref": "#/$defs/ProfileChunk"
          }
        }
      },
      "required": [
        "schema",
        "id",
        "revision",
        "name",
        "notes",
        "preferences"
      ],
      "additionalProperties": false,
      "x-ontology": {
        "class": "urn:zendo:concierge:v1#GuestProfile",
        "describes": "urn:zendo:concierge:v1#Guest",
        "representation": "Reusable Zendo context about a Guest. id remains a legacy guest-ID alias; profileId identifies this profile."
      }
    },
    "TripBrief": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.trip-brief/v1"
        },
        "id": {
          "type": "string",
          "maxLength": 120
        },
        "guestId": {
          "type": "string",
          "maxLength": 120
        },
        "revision": {
          "type": "integer",
          "minimum": 1
        },
        "purpose": {
          "type": "string",
          "minLength": 1,
          "maxLength": 160
        },
        "destination": {
          "const": "Vancouver"
        },
        "start": {
          "type": "string",
          "format": "date"
        },
        "end": {
          "type": "string",
          "format": "date"
        },
        "budget": {
          "type": "number",
          "minimum": 1000,
          "maximum": 100000
        },
        "currency": {
          "const": "CAD"
        },
        "beds": {
          "type": "integer",
          "minimum": 1,
          "maximum": 4
        },
        "guests": {
          "type": "integer",
          "minimum": 1,
          "maximum": 8
        },
        "mustHaves": {
          "type": "array",
          "maxItems": 8,
          "items": {
            "enum": [
              "Workspace",
              "Parking",
              "Pet friendly",
              "Gym",
              "Water view"
            ]
          }
        },
        "notes": {
          "type": "string",
          "maxLength": 2000
        }
      },
      "required": [
        "schema",
        "id",
        "guestId",
        "revision",
        "purpose",
        "destination",
        "start",
        "end",
        "budget",
        "currency",
        "beds",
        "guests",
        "mustHaves",
        "notes"
      ],
      "additionalProperties": false
    },
    "CaptureSettings": {
      "type": "object",
      "properties": {
        "trainingReviewEnabled": {
          "type": "boolean"
        }
      },
      "required": [
        "trainingReviewEnabled"
      ],
      "additionalProperties": false
    },
    "ContextReference": {
      "type": "object",
      "required": [
        "id",
        "guestId",
        "scope",
        "briefId",
        "label",
        "category",
        "lat",
        "lng",
        "notes",
        "status",
        "source",
        "createdBy",
        "updatedBy",
        "confirmedBy"
      ],
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 120
        },
        "guestId": {
          "type": "string",
          "maxLength": 120
        },
        "scope": {
          "enum": [
            "guest",
            "brief"
          ]
        },
        "briefId": {
          "type": [
            "string",
            "null"
          ]
        },
        "label": {
          "type": "string",
          "minLength": 1,
          "maxLength": 120
        },
        "category": {
          "enum": [
            "Work",
            "Lifestyle",
            "Transport",
            "Other"
          ]
        },
        "lat": {
          "type": "number",
          "minimum": 49.15,
          "maximum": 49.4
        },
        "lng": {
          "type": "number",
          "minimum": -123.35,
          "maximum": -122.9
        },
        "notes": {
          "type": "string",
          "maxLength": 2000
        },
        "status": {
          "enum": [
            "suggested",
            "confirmed"
          ]
        },
        "placeId": {
          "type": [
            "string",
            "null"
          ]
        },
        "source": {
          "type": "object"
        },
        "createdBy": {
          "type": "object"
        },
        "updatedBy": {
          "type": "object"
        },
        "confirmedBy": {
          "type": [
            "object",
            "null"
          ]
        },
        "relationship": {
          "enum": [
            "pinned",
            "relevant",
            "profile-context",
            "itinerary-option"
          ],
          "description": "Reference role. itinerary-option is a brief-scoped candidate place, not a reservation, scheduled visit or durable guest favourite."
        },
        "preferenceEvidence": {
          "type": [
            "object",
            "null"
          ],
          "description": "Guest-stated interest, recordedBy/recordedAt and guestConfirmation null. Required by service for new profile pins."
        },
        "planningOrigin": {
          "type": [
            "object",
            "null"
          ],
          "description": "Planning session/point IDs, dataset hash, original source/evidence and generating actor, assigned by service."
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "scope": {
                "const": "guest"
              }
            }
          },
          "then": {
            "properties": {
              "briefId": {
                "type": "null"
              }
            }
          },
          "else": {
            "properties": {
              "briefId": {
                "type": "string",
                "minLength": 1
              }
            }
          }
        }
      ],
      "additionalProperties": true
    },
    "Guest": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.guest/v1"
        },
        "id": {
          "type": "string",
          "maxLength": 120
        },
        "revision": {
          "type": "integer",
          "minimum": 1
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "company": {
          "type": "string",
          "maxLength": 100
        }
      },
      "required": [
        "schema",
        "id",
        "revision",
        "name"
      ],
      "additionalProperties": false,
      "x-ontology": {
        "class": "urn:zendo:concierge:v1#Guest",
        "subClassOf": "https://zenith-research.ca/ontology/terms/Person",
        "canonicalRelease": "v0.8.0",
        "representation": "Local synthetic person identity; no verified Rolodex binding."
      }
    },
    "ProfileChunk": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.profile-chunk/v1"
        },
        "id": {
          "type": "string"
        },
        "guestId": {
          "type": "string"
        },
        "profileId": {
          "type": "string"
        },
        "topicId": {
          "enum": [
            "feeling-at-home",
            "daily-rhythm",
            "household-needs",
            "errands-services",
            "interests-personal-style",
            "general-preferences",
            "notes"
          ]
        },
        "response": {
          "type": "string",
          "maxLength": 4000
        },
        "revision": {
          "type": "integer",
          "minimum": 0
        },
        "basis": {
          "enum": [
            "guest-provided",
            "concierge-observation",
            "agent-suggested",
            "unattributed"
          ]
        },
        "updatedBy": {
          "type": [
            "object",
            "null"
          ]
        },
        "updatedAt": {
          "type": [
            "string",
            "null"
          ]
        },
        "guestConfirmation": {
          "type": "null",
          "description": "Guest-only; no verified guest confirmation endpoint is implemented."
        },
        "contributions": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "revision",
              "response",
              "basis",
              "enteredBy",
              "at"
            ]
          }
        }
      },
      "required": [
        "schema",
        "id",
        "guestId",
        "profileId",
        "topicId",
        "response",
        "revision",
        "basis",
        "updatedBy",
        "updatedAt",
        "guestConfirmation",
        "contributions"
      ],
      "additionalProperties": false,
      "allOf": [
        {
          "if": {
            "properties": {
              "topicId": {
                "const": "notes"
              }
            }
          },
          "then": {
            "properties": {
              "response": {
                "maxLength": 2000
              }
            }
          }
        }
      ]
    },
    "Recommendation": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.recommendation/v1"
        },
        "id": {
          "type": "string"
        },
        "guestId": {
          "type": "string"
        },
        "briefId": {
          "type": "string"
        },
        "briefRevision": {
          "type": "integer",
          "minimum": 1
        },
        "propertyId": {
          "type": "string"
        },
        "reason": {
          "type": "string",
          "minLength": 1,
          "maxLength": 2000
        },
        "createdBy": {
          "type": "object"
        },
        "createdAt": {
          "type": "string"
        },
        "status": {
          "enum": [
            "current",
            "review-needed",
            "withdrawn"
          ]
        },
        "legacy": {
          "type": "boolean"
        }
      },
      "required": [
        "schema",
        "id",
        "guestId",
        "briefId",
        "briefRevision",
        "propertyId",
        "reason",
        "createdBy",
        "createdAt",
        "status"
      ],
      "additionalProperties": false
    },
    "Selection": {
      "type": "object",
      "properties": {
        "recommendationId": {
          "type": "string"
        },
        "briefId": {
          "type": "string"
        },
        "briefRevision": {
          "type": "integer",
          "minimum": 1
        },
        "propertyId": {
          "type": "string"
        },
        "reason": {
          "type": "string"
        },
        "selectedBy": {
          "type": "string"
        },
        "selectedAt": {
          "type": "string"
        }
      },
      "required": [
        "propertyId",
        "reason",
        "selectedBy",
        "selectedAt"
      ],
      "additionalProperties": false
    },
    "PlanningPoint": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "entityId": {
          "type": "string"
        },
        "kind": {
          "const": "place"
        },
        "title": {
          "type": "string",
          "maxLength": 120
        },
        "category": {
          "enum": [
            "Work",
            "Lifestyle",
            "Transport",
            "Other"
          ]
        },
        "lat": {
          "type": "number",
          "minimum": 49.15,
          "maximum": 49.4
        },
        "lng": {
          "type": "number",
          "minimum": -123.35,
          "maximum": -122.9
        },
        "reason": {
          "type": "string"
        },
        "evidence": {
          "type": "array"
        },
        "sourceUrl": {
          "type": [
            "string",
            "null"
          ]
        },
        "source": {
          "type": "object"
        },
        "method": {
          "type": "string"
        },
        "generatedBy": {
          "type": "object"
        },
        "status": {
          "const": "generated"
        }
      },
      "required": [
        "id",
        "entityId",
        "kind",
        "title",
        "category",
        "lat",
        "lng",
        "reason",
        "evidence",
        "sourceUrl",
        "source",
        "method",
        "generatedBy",
        "status"
      ],
      "additionalProperties": false
    },
    "PlanningSession": {
      "type": "object",
      "properties": {
        "schema": {
          "const": "zendo.planning-session/v1"
        },
        "id": {
          "type": "string"
        },
        "guestId": {
          "type": "string"
        },
        "briefId": {
          "type": "string"
        },
        "briefRevision": {
          "type": "integer",
          "minimum": 1
        },
        "input": {
          "type": "object"
        },
        "inputHash": {
          "type": "string"
        },
        "workspaceVersion": {
          "type": "integer",
          "minimum": 1
        },
        "createdBy": {
          "type": "object"
        },
        "createdAt": {
          "type": "string"
        },
        "method": {
          "type": "string"
        },
        "retention": {
          "enum": [
            "working",
            "retained"
          ]
        },
        "points": {
          "type": "array",
          "maxItems": 50,
          "items": {
            "$ref": "#/$defs/PlanningPoint"
          }
        },
        "datasetHash": {
          "type": "string"
        },
        "keptAt": {
          "type": "string"
        },
        "keptBy": {
          "type": "object"
        }
      },
      "required": [
        "schema",
        "id",
        "guestId",
        "briefId",
        "briefRevision",
        "input",
        "inputHash",
        "workspaceVersion",
        "createdBy",
        "createdAt",
        "method",
        "retention",
        "points",
        "datasetHash"
      ],
      "additionalProperties": false
    }
  }
}
