{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://www.anguskit.com/schema/anguscopilot/1.0.0/databases.json",
  "title": "Business Database Configuration",
  "description": "业务数据库集成配置块（与 §20 对齐）。让 Agent 通过 JdbcTool 安全访问企业的多个业务数据库（MySQL / PostgreSQL / Oracle / SQL Server / Doris / ClickHouse / Hive 等）。",
  "type": "object",
  "properties": {

    "sources": {
      "description": "业务数据源列表（W13 新增）。每个数据源独立连接池 + 安全策略。 [beta]",
      "type": "array",
      "minItems": 1,
      "uniqueItems": true,
      "items": {
        "type": "object",
        "required": ["id", "type", "host", "database", "credentialRef"],
        "properties": {
          "id": {
            "description": "数据源唯一标识（与 tool://db/<id>/<op>@<v> 引用对应）。 [beta]",
            "$ref": "common.json#/$defs/Identifier"
          },
          "type": {
            "description": "数据库类型。 [beta]",
            "type": "string",
            "enum": ["mysql", "mariadb", "postgresql", "oracle", "sqlserver", "doris", "clickhouse", "hive", "db2"]
          },
          "version": {
            "description": "数据库版本（DB1 约束：type=oracle 时必填）。 [beta]",
            "type": "string"
          },
          "host": { "type": "string", "minLength": 1 },
          "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
          "database": { "type": "string", "minLength": 1 },
          "credentialRef": {
            "description": "数据库连接凭证引用。 [beta]",
            "$ref": "common.json#/$defs/SecretRef"
          },
          "readOnly": {
            "description": "是否只读数据源（true 时禁止注册 safety=DESTRUCTIVE 的 operation，DB2 约束）。 [beta]",
            "type": "boolean",
            "default": false
          },
          "readReplica": {
            "description": "只读副本配置。 [beta]",
            "type": "object",
            "properties": {
              "host": { "type": "string", "minLength": 1 },
              "port": { "type": "integer", "minimum": 1, "maximum": 65535 },
              "credentialRef": { "$ref": "common.json#/$defs/SecretRef" }
            },
            "required": ["host", "credentialRef"],
            "patternProperties": { "^x-": true },
            "unevaluatedProperties": false
          },
          "pool": {
            "description": "连接池配置（与 §13.3 bulkhead.byDataSource 对应）。 [beta]",
            "type": "object",
            "properties": {
              "maxConnections": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 10 },
              "minIdle": { "type": "integer", "minimum": 0, "default": 0 },
              "connectionTimeout": { "$ref": "common.json#/$defs/Duration", "default": "3s" },
              "idleTimeout": { "$ref": "common.json#/$defs/Duration", "default": "10m" },
              "maxLifetime": { "$ref": "common.json#/$defs/Duration", "default": "30m" },
              "leakDetectionThreshold": { "$ref": "common.json#/$defs/Duration" }
            },
            "patternProperties": { "^x-": true },
            "unevaluatedProperties": false
          },
          "safety": {
            "description": "数据源级安全策略。 [beta]",
            "type": "object",
            "properties": {
              "allowedSchemas": {
                "type": "array",
                "items": { "type": "string", "minLength": 1 },
                "uniqueItems": true
              },
              "forbiddenSchemas": {
                "type": "array",
                "items": { "type": "string", "minLength": 1 },
                "uniqueItems": true
              },
              "forbiddenTables": {
                "type": "array",
                "items": { "type": "string", "minLength": 1 },
                "uniqueItems": true
              },
              "maxRowsAffected": {
                "description": "全局写操作影响行数上限。 [beta]",
                "type": "integer",
                "minimum": 1,
                "default": 100
              },
              "maxRowsReturned": {
                "description": "全局查询返回行数上限。 [beta]",
                "type": "integer",
                "minimum": 1,
                "default": 10000
              },
              "maxResultBytes": {
                "description": "单次查询返回字节上限。 [beta]",
                "type": "integer",
                "minimum": 1024
              },
              "defaultTimeout": { "$ref": "common.json#/$defs/Duration", "default": "5s" }
            },
            "patternProperties": { "^x-": true },
            "unevaluatedProperties": false
          },
          "operations": {
            "description": "本数据源支持的 Operation 定义。 [beta]",
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "object",
              "required": ["name", "safety"],
              "properties": {
                "name": {
                  "description": "Operation 名称（与 tool://db/<dsId>/<name>@<version> 对应）。 [beta]",
                  "$ref": "common.json#/$defs/Identifier"
                },
                "version": {
                  "$ref": "common.json#/$defs/SemVer",
                  "default": "1.0.0"
                },
                "description": { "type": "string" },
                "mode": {
                  "description": "Operation 实现模式（DB3 约束：llm-generated 必须配 schemaRef + sandboxMode）。 [beta]",
                  "type": "string",
                  "enum": ["parameterized", "llm-generated"],
                  "default": "parameterized"
                },
                "sql": {
                  "description": "参数化 SQL 模板（mode=parameterized 时必填，DB5 隐含约束）。占位符使用 :name 形式。 [beta]",
                  "type": "string",
                  "minLength": 1
                },
                "parameters": {
                  "description": "Operation 参数定义（mode=parameterized 时强制非空，DB5 约束）。 [beta]",
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": ["name", "type"],
                    "properties": {
                      "name": {
                        "description": "参数名（数据库参数名通常为驼峰或下划线）。 [beta]",
                        "type": "string",
                        "pattern": "^[a-zA-Z_][a-zA-Z0-9_]*$",
                        "minLength": 1,
                        "maxLength": 64
                      },
                      "type": {
                        "type": "string",
                        "enum": ["string", "integer", "number", "boolean", "date", "date-time", "decimal", "uuid"]
                      },
                      "required": { "type": "boolean", "default": true },
                      "default": { },
                      "schema": {
                        "description": "JSON Schema（mode=parameterized 时必填）。 [beta]",
                        "$ref": "common.json#/$defs/JsonSchemaRef"
                      }
                    },
                    "patternProperties": { "^x-": true },
                    "unevaluatedProperties": false
                  }
                },
                "safety": {
                  "type": "string",
                  "enum": ["SAFE", "SENSITIVE", "DESTRUCTIVE"]
                },
                "approval": {
                  "description": "DESTRUCTIVE 时必填（DB4 约束）。 [beta]",
                  "type": "object",
                  "required": ["channel"],
                  "properties": {
                    "channel": {
                      "type": "string",
                      "enum": ["web", "slack", "lark", "dingtalk", "email"]
                    },
                    "approvers": {
                      "type": "array",
                      "items": { "type": "string", "minLength": 1 },
                      "minItems": 1
                    },
                    "timeout": { "$ref": "common.json#/$defs/Duration", "default": "30m" }
                  },
                  "patternProperties": { "^x-": true },
                  "unevaluatedProperties": false
                },
                "schemaRef": {
                  "description": "LLM-generated 模式下的表结构 + 列说明引用（mode=llm-generated 时必填，DB3 约束）。 [beta]",
                  "type": "string",
                  "minLength": 1
                },
                "sandboxMode": {
                  "description": "LLM-generated 模式下的沙箱策略（mode=llm-generated 时必填，DB3 约束）。 [beta]",
                  "type": "string",
                  "enum": ["explain-first", "dry-run", "isolated-replica"]
                },
                "constraints": {
                  "description": "LLM-generated 模式下的约束。 [beta]",
                  "type": "object",
                  "properties": {
                    "readOnly": { "type": "boolean", "default": true },
                    "maxTables": { "type": "integer", "minimum": 1, "default": 5 },
                    "forbidJoinTypes": {
                      "type": "array",
                      "items": { "type": "string", "enum": ["CROSS", "NATURAL", "FULL_OUTER"] },
                      "uniqueItems": true
                    },
                    "maxLimit": { "type": "integer", "minimum": 1, "default": 1000 }
                  },
                  "patternProperties": { "^x-": true },
                  "unevaluatedProperties": false
                },
                "cache": {
                  "type": "object",
                  "properties": {
                    "enabled": { "type": "boolean", "default": false },
                    "ttl": { "$ref": "common.json#/$defs/Duration" },
                    "keyTemplate": { "type": "string" }
                  },
                  "patternProperties": { "^x-": true },
                  "unevaluatedProperties": false
                },
                "timeout": { "$ref": "common.json#/$defs/Duration" },
                "fetchSize": { "type": "integer", "minimum": 1, "maximum": 10000 },
                "pageable": { "type": "boolean", "default": false }
              },
              "patternProperties": { "^x-": true },
              "$comment": "Operation 内部跨字段约束：DB3/DB4/DB5。",
              "allOf": [
                {
                  "$comment": "DB3: mode=llm-generated 必须 schemaRef + sandboxMode。",
                  "if": {
                    "properties": { "mode": { "const": "llm-generated" } },
                    "required": ["mode"]
                  },
                  "then": {
                    "required": ["schemaRef", "sandboxMode"],
                    "not": { "required": ["sql"] }
                  }
                },
                {
                  "$comment": "DB5: mode=parameterized 必须 sql + parameters（非空）。",
                  "if": {
                    "properties": { "mode": { "const": "parameterized" } },
                    "required": ["mode"]
                  },
                  "then": {
                    "required": ["sql"],
                    "not": { "required": ["schemaRef"] }
                  }
                },
                {
                  "$comment": "DB4: safety=DESTRUCTIVE 必须 approval。",
                  "if": {
                    "properties": { "safety": { "const": "DESTRUCTIVE" } },
                    "required": ["safety"]
                  },
                  "then": {
                    "required": ["approval"]
                  }
                }
              ],
              "unevaluatedProperties": false
            }
          }
        },
        "patternProperties": { "^x-": true },
        "$comment": "Source 内部跨字段约束：DB1/DB2。",
        "allOf": [
          {
            "$comment": "DB1: type=oracle 必须 version。",
            "if": {
              "properties": { "type": { "const": "oracle" } },
              "required": ["type"]
            },
            "then": {
              "required": ["version"]
            }
          },
          {
            "$comment": "DB2: readOnly=true 时 operations 中禁止 safety=DESTRUCTIVE。",
            "if": {
              "properties": { "readOnly": { "const": true } },
              "required": ["readOnly"]
            },
            "then": {
              "properties": {
                "operations": {
                  "items": {
                    "not": {
                      "properties": {
                        "safety": { "const": "DESTRUCTIVE" }
                      },
                      "required": ["safety"]
                    }
                  }
                }
              }
            }
          }
        ],
        "unevaluatedProperties": false
      }
    }
  },
  "patternProperties": {
    "^x-": true
  },
  "unevaluatedProperties": false
}
