{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://docs.qauth.dev/schemas/events/admin.change_applied.v1-rc.0.json",
  "title": "urn:qauth:event:admin.change_applied:v1-rc.0",
  "description": "The admin.change_applied event, v1-rc.0. An administrator, a service account or an operator changed something in the realm through an admin operation. Emitted for every such change, in its transaction; no setting turns it off. The admin events of a realm form one hash chain.",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
      "description": "The event id, a UUIDv7. One event keeps one id on every route and every retry, so a receiver drops duplicates by it. It is the `webhook-id` of a webhook and the source of an SSF `jti`."
    },
    "type": {
      "type": "string",
      "const": "urn:qauth:event:admin.change_applied:v1-rc.0",
      "description": "The event type, `urn:qauth:event:<name>:v<N>`, or `:v<N>-rc.<M>` for a release candidate. The registry lists every type."
    },
    "time": {
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$",
      "description": "When the event happened, as an RFC 3339 time in UTC. Not when it was delivered."
    },
    "realm": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The id of the realm the event happened in."
    },
    "category": {
      "type": "string",
      "const": "admin",
      "description": "`user`: an end user's own activity. `admin`: an administrator's change. Fixed by the type."
    },
    "actor": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "`user`: a person, signed in. `client`: an OAuth client acting for itself or, with `delegationChain`, as an agent for the subject. `system`: QAuth itself, such as a scheduled job. `operator_cli`: an operator on the server host, through a QAuth command-line tool.",
          "x-extensible-enum": [
            "user",
            "client",
            "system",
            "operator_cli"
          ]
        },
        "id": {
          "description": "The actor's identifier: a user id, a client's `client_id`, or the operating-system user for `operator_cli`. Absent for `system`.",
          "type": "string",
          "minLength": 1,
          "maxLength": 255
        },
        "delegationChain": {
          "description": "The RFC 8693 `act` chain of a delegated request, as `client_id` values: the acting agent first, then each earlier actor. Absent when nothing was delegated.",
          "minItems": 1,
          "maxItems": 16,
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          }
        }
      },
      "required": [
        "type"
      ],
      "description": "Who or what caused the event."
    },
    "subject": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "description": "What kind of thing the subject is.",
          "x-extensible-enum": [
            "user",
            "client",
            "api_key",
            "ssf_stream"
          ]
        },
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "description": "The subject's identifier: a user id, a client's `client_id`, an API key id or a Shared Signals Framework `stream_id`. It stays valid after the subject is deleted."
        }
      },
      "required": [
        "type",
        "id"
      ],
      "description": "What the event is about."
    },
    "client": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "maxLength": 255,
          "description": "The client's `client_id`."
        }
      },
      "required": [
        "id"
      ],
      "description": "The OAuth client the request came through."
    },
    "request": {
      "type": "object",
      "properties": {
        "traceId": {
          "description": "The id under which QAuth logged the request: the `trace_id` of a problem document from the same request.",
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "ip": {
          "description": "The end user's IP address, as QAuth derived it from the request. An IPv4-mapped IPv6 address is written in its IPv4 form.",
          "anyOf": [
            {
              "type": "string",
              "format": "ipv4",
              "pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"
            },
            {
              "type": "string",
              "format": "ipv6",
              "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$"
            }
          ]
        },
        "userAgent": {
          "description": "The `User-Agent` header, cut to 1024 characters.",
          "type": "string",
          "maxLength": 1024
        }
      },
      "description": "The HTTP request that caused the event."
    },
    "data": {
      "type": "object",
      "properties": {
        "operation": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128,
          "pattern": "^[a-z][a-z0-9_]*(?:\\.[a-z][a-z0-9_]*)*$",
          "description": "The operation's id in the permission catalog, such as `realms.policies.write` (ADR-019 Decision 7)."
        },
        "target": {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64,
              "pattern": "^[a-z][a-z0-9_]*$",
              "description": "What kind of thing the operation changed, as a `snake_case` code such as `realm`, `client` or `webhook_subscription`. The set grows with the admin API."
            },
            "id": {
              "type": "string",
              "minLength": 1,
              "maxLength": 255,
              "description": "The changed thing's identifier, such as a realm id or a `client_id`. It stays valid after the thing is deleted."
            }
          },
          "required": [
            "type",
            "id"
          ],
          "description": "What the operation changed."
        },
        "diff": {
          "maxItems": 1024,
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "path": {
                "type": "string",
                "maxLength": 1024,
                "pattern": "^(?:\\/(?:[^~/]|~[01])*)+$",
                "description": "The changed field, as a JSON Pointer (RFC 6901) into the resource, such as `/smtp/host`."
              },
              "before": {
                "description": "The value before the operation. Absent when the field did not exist. A secret field holds `***`.",
                "$ref": "#/$defs/__schema0"
              },
              "after": {
                "description": "The value after the operation. Absent when the field no longer exists. A secret field holds `***`.",
                "$ref": "#/$defs/__schema0"
              }
            },
            "required": [
              "path"
            ],
            "description": "One changed field."
          },
          "description": "What the operation changed in the target, field by field. Only changed fields are listed. A nested object is diffed member by member; any other value, an array included, is shown whole. Every secret value is `***`."
        },
        "approvals": {
          "maxItems": 16,
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "approverId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 255,
                "description": "The account id of the admin who approved the operation."
              },
              "credentialId": {
                "type": "string",
                "minLength": 1,
                "maxLength": 1400,
                "description": "The id of the passkey credential the approval was given with. The rule that an approver uses a credential not registered to the requester is checked against it."
              },
              "approverCreatedBy": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "Who created the account: `user`, an admin; `client`, a service account; `operator_cli`, an operator on the server host, such as a break-glass enrolment; `system`, QAuth itself.",
                    "x-extensible-enum": [
                      "user",
                      "client",
                      "system",
                      "operator_cli"
                    ]
                  },
                  "id": {
                    "description": "The creator's identifier: an account id, a `client_id`, or the operating-system user for `operator_cli`. Absent for `system`.",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255
                  }
                },
                "required": [
                  "type"
                ],
                "description": "Who created the approver's account. The two-admin rule binds accounts, not people, so the event shows it."
              },
              "approvedAt": {
                "description": "When the approval was given, as an RFC 3339 time in UTC.",
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
              }
            },
            "required": [
              "approverId",
              "credentialId",
              "approverCreatedBy"
            ],
            "description": "One approval of the operation."
          },
          "description": "The approvals the operation ran on, both of a two-admin operation. Empty when it needed none."
        }
      },
      "required": [
        "operation",
        "target",
        "diff",
        "approvals"
      ],
      "description": "The type's own payload. Its schema is the type's."
    }
  },
  "required": [
    "id",
    "type",
    "time",
    "realm",
    "category",
    "data"
  ],
  "$defs": {
    "__schema0": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "null"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/__schema0"
          }
        },
        {
          "type": "object",
          "propertyNames": {
            "type": "string"
          },
          "additionalProperties": {
            "$ref": "#/$defs/__schema0"
          }
        }
      ]
    }
  }
}
