{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://ihgiz.net/api/engine/v0/documents/state-graph.schema.json","title":"State graph","description":"The stages one thing goes through — an Event, a participant's part in it, or a template entity such as a membership — and the named transitions between them. A template supplies its graphs as data; the lifecycle engine runs them. Guards and effects are named capabilities implemented in code; a graph names them and never contains code (decision D5).","type":"object","required":["subject"],"properties":{"subject":{"description":"What the graph moves: the Event itself, one participant's part in an Event, or a template entity.","enum":["event","participation","entity"]},"description":{"type":"string"},"initial":{"$ref":"#/$defs/key"},"states":{"type":"object","minProperties":1,"propertyNames":{"$ref":"#/$defs/key"},"additionalProperties":{"$ref":"#/$defs/state"}},"transitions":{"type":"array","items":{"$ref":"#/$defs/transition"}},"regions":{"description":"Parallel regions: independent sub-graphs of the same subject, such as fulfilment and payment of one order. A graph has either states or regions.","type":"object","minProperties":2,"propertyNames":{"$ref":"#/$defs/key"},"additionalProperties":{"$ref":"#/$defs/region"}}},"oneOf":[{"required":["initial","states","transitions"],"not":{"required":["regions"]}},{"required":["regions"],"not":{"anyOf":[{"required":["states"]},{"required":["initial"]},{"required":["transitions"]}]}}],"additionalProperties":false,"$defs":{"key":{"type":"string","pattern":"^[a-z][a-z0-9]*(-[a-z0-9]+)*$","maxLength":64},"capability":{"description":"A named guard or effect implemented in code, e.g. payment.deposit_received.","type":"string","pattern":"^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$"},"phase":{"description":"The engine's fixed vocabulary. Every state maps to one, so reports, reminders, refunds and webhooks work in every template unchanged.","enum":["draft","pending","confirmed","active","completed","cancelled","expired","failed"]},"labels":{"description":"Display names by BCP 47 language tag. English is required as the fallback.","type":"object","required":["en"],"propertyNames":{"pattern":"^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$"},"additionalProperties":{"type":"string","minLength":1}},"state":{"type":"object","required":["phase"],"properties":{"phase":{"$ref":"#/$defs/phase"},"labels":{"$ref":"#/$defs/labels"},"participationStatus":{"description":"For participation graphs: the JSCalendar participationStatus (iCalendar PARTSTAT) this state is published as.","enum":["needs-action","accepted","declined","tentative","delegated"]},"eventStatus":{"description":"For event graphs: the JSCalendar status (iCalendar STATUS) this state is published as. When absent it follows from the phase.","enum":["tentative","confirmed","cancelled"]}},"additionalProperties":false},"actor":{"description":"Who may fire a transition. participant: someone taking part; staff: the tenant's team; organizer: the tenant's owner role; operator: IHGIZ HQ; system: the engine itself (timers, cascades); integration: an API key.","enum":["participant","staff","organizer","operator","system","integration"]},"transition":{"type":"object","required":["name","from","to","by"],"properties":{"name":{"$ref":"#/$defs/key"},"from":{"description":"States the transition may start from; [\"*\"] means any state.","type":"array","minItems":1,"uniqueItems":true,"items":{"anyOf":[{"$ref":"#/$defs/key"},{"const":"*"}]}},"to":{"$ref":"#/$defs/key"},"by":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/$defs/actor"}},"guards":{"type":"array","uniqueItems":true,"items":{"$ref":"#/$defs/capability"}},"effects":{"type":"array","uniqueItems":true,"items":{"$ref":"#/$defs/capability"}},"changes":{"description":"Event properties this transition may change, as JSCalendar property names (e.g. start, duration, locations). Absent: none.","type":"array","uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z@][A-Za-z0-9.:@-]*$"}},"itip":{"description":"The iTIP (RFC 5546) method this transition is announced with, if participants are sent calendar messages.","enum":["PUBLISH","REQUEST","REPLY","ADD","CANCEL","REFRESH","COUNTER","DECLINECOUNTER","none"]},"intents":{"description":"Message intents raised: which participants are told what. The router picks channel and wording.","type":"array","uniqueItems":true,"items":{"type":"string","pattern":"^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)+$"}},"labels":{"$ref":"#/$defs/labels"}},"additionalProperties":false},"region":{"type":"object","required":["initial","states","transitions"],"properties":{"description":{"type":"string"},"initial":{"$ref":"#/$defs/key"},"states":{"type":"object","minProperties":1,"propertyNames":{"$ref":"#/$defs/key"},"additionalProperties":{"$ref":"#/$defs/state"}},"transitions":{"type":"array","items":{"$ref":"#/$defs/transition"}}},"additionalProperties":false}}}