{
  "repo": "tidbcloud/dataapps",
  "binary": "sqleditor",
  "binary_path": "cmd/sqleditor/main.go",
  "dependencies": {
    "Runtime SqlEditorLifecycle.LoadConfig": {
      "infrastructure": {
        "filesystem": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "READ FILE",
              "trigger": "Load the central config file before any database, eventbus, or network listener starts",
              "conditions": [
                "config-path flag is provided or the default /etc/dbaas/config.yaml is present"
              ],
              "implementation": "config.InitConfig(configPath) -> viper.ReadInConfig()"
            }
          ]
        },
        "environment": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "LOAD ENV OVERRIDES",
              "trigger": "Allow environment variables to override config values after reading the YAML file",
              "conditions": [
                "Always"
              ],
              "implementation": "config.InitConfig(configPath) -> viper.AutomaticEnv()"
            }
          ]
        }
      },
      "services": []
    },
    "Runtime SqlEditorLifecycle.SetupObservability": {
      "infrastructure": {},
      "services": [
        {
          "name": "sentry",
          "target_interface": "Sentry client initialization",
          "operation_type": "sdk_init",
          "target_repo": "getsentry/sentry-go",
          "conditions": [
            "Always during startup"
          ],
          "operations": [
            {
              "operation": "INIT CLIENT",
              "trigger": "Initialize the process-wide Sentry client before the HTTP and gRPC servers start",
              "conditions": [
                "Always"
              ],
              "implementation": "sentry.SetupLoggerAndSentry(dsn, env, logLevel) -> sentry.Init(opts)"
            }
          ]
        },
        {
          "name": "jaeger",
          "target_interface": "InitJaeger(componentName)",
          "operation_type": "tracing_init",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "Always during startup"
          ],
          "operations": [
            {
              "operation": "INIT TRACING",
              "trigger": "Initialize Jaeger tracing for sqleditor",
              "conditions": [
                "Always"
              ],
              "implementation": "titracing.InitJaeger(componentName)"
            }
          ]
        }
      ]
    },
    "Runtime SqlEditorLifecycle.ConnectDatabase": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always during startup"
          ],
          "operations": [
            {
              "operation": "OPEN DB HANDLE",
              "trigger": "Initialize the shared GORM connection used by settings, SQL files, messages, and oplogs",
              "conditions": [
                "mysql.host and mysql.password are present in config"
              ],
              "implementation": "database.Connect(ctx, centralConfig) -> gorm.Open(mysql.Open(url), &gorm.Config{...})"
            }
          ]
        }
      },
      "services": []
    },
    "Runtime SqlEditorLifecycle.StartEventbus": {
      "infrastructure": {},
      "services": [
        {
          "name": "tieventbus",
          "target_interface": "Eventbus.RegisterHandler + Eventbus.Run",
          "operation_type": "eventbus_consumer",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "centralConfig.GardenerConfig.Env != \"local\""
          ],
          "operations": [
            {
              "operation": "REGISTER HANDLER",
              "trigger": "Register the user-settings sync consumer before the eventbus starts running",
              "conditions": [
                "centralConfig.GardenerConfig.Env != \"local\""
              ],
              "implementation": "events.RegisterUserSettingsEventHandler(ctx) -> eventbus.Get().RegisterEventHandleFunc(...)"
            },
            {
              "operation": "RUN CONSUMER LOOP",
              "trigger": "Start the eventbus consumer loop for registered sqleditor handlers",
              "conditions": [
                "RegisterUserSettingsEventHandler(ctx) succeeded"
              ],
              "implementation": "eventbus.Get().Run() -> tieventbusImpl.Run()"
            }
          ]
        }
      ]
    },
    "Runtime SqlEditorLifecycle.StartAuditLog": {
      "infrastructure": {},
      "services": [
        {
          "name": "audit-log-sdk",
          "target_interface": "InitAuditLogSDK",
          "operation_type": "sdk_init",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "server.localMode == false"
          ],
          "operations": [
            {
              "operation": "INIT SDK",
              "trigger": "Initialize the audit-log SDK before serving user traffic",
              "conditions": [
                "server.localMode == false"
              ],
              "implementation": "auditlogsdk.InitAuditLogSDK(ctx, time.Second)"
            }
          ]
        }
      ]
    },
    "Runtime SqlEditorLifecycle.RegisterHTTPRoutes": {
      "infrastructure": {},
      "services": [
        {
          "name": "account-provider",
          "target_interface": "AccountAPIService client connection",
          "operation_type": "client_init",
          "target_repo": "tidbcloud/account",
          "conditions": [
            "Always during startup"
          ],
          "operations": [
            {
              "operation": "CREATE CLIENT",
              "trigger": "Prepare the account-provider gRPC client used later by auth and RBAC middlewares",
              "conditions": [
                "Always"
              ],
              "implementation": "installAuthAndRBACPlugin -> grpc.GetAccountProviderSvcClient() -> tigrpc.NewClientConn(config.Global().GrpcConfig.AccountProviderSvcAddr, ...)"
            }
          ]
        }
      ]
    },
    "Runtime SqlEditorLifecycle.RegisterGRPCServices": {
      "infrastructure": {},
      "services": []
    },
    "Runtime SqlEditorLifecycle.StartMetricsServer": {
      "infrastructure": {},
      "services": []
    },
    "Runtime SqlEditorLifecycle.StartGRPCServer": {
      "infrastructure": {},
      "services": []
    },
    "Runtime SqlEditorLifecycle.StartHTTPServer": {
      "infrastructure": {},
      "services": []
    },
    "HTTP GET /healthz": {
      "infrastructure": {},
      "services": []
    },
    "HTTP GET /swagger/*any": {
      "infrastructure": {},
      "services": []
    },
    "HTTP PUT /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/settings": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "Settings JSON binds successfully",
            "param.limit <= 2000"
          ],
          "operations": [
            {
              "operation": "SELECT + INSERT/UPDATE",
              "trigger": "Load or update the user's SQL editor settings row",
              "conditions": [
                "service.UpdateUserSettings(settings) is reached"
              ],
              "implementation": "service.UpdateUserSettings -> repository.UpdateSettings -> DB.Table(\"sql_editor_settings\").First(...); Save(...) or Update(...)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/settings": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the stored SQL editor settings, creating a default row on first access",
              "conditions": [
                "service.ShowSettings(ctx, settings) is reached"
              ],
              "implementation": "service.ShowSettings -> repository.ShowUserSettings -> DB.Table(\"sql_editor_settings\").First(...); Save(&param) on record-not-found"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "service.ShowSettings(ctx, settings) is reached after reading user settings"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled",
              "conditions": [
                "Always once ShowSettings reaches service.ShowDataAppSettings"
              ],
              "implementation": "service.ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, &dataapi.ListDataAppReq{ProjectId: ..., AppTypes: [\"chat2query\"]})"
            }
          ]
        }
      ]
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/statements": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "StatementParam JSON binds successfully"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's SQL editor settings in order to determine the result-row limit",
              "conditions": [
                "service.Statements(...) is reached"
              ],
              "implementation": "service.Statements -> ShowSettingsLimit -> ShowSettings -> repository.ShowUserSettings"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist a statement-execution message row after the request finishes",
              "conditions": [
                "service.Statements(...) returned either success or error",
                "createLog(ctx, message) is reached"
              ],
              "implementation": "createLog(ctx, message) -> service.CreateMessage(message) -> repository.CreateMessage -> DB.Table(\"sql_editor_message\").Save(&param)"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the exec_sql oplog asynchronously after the request reaches the background logging goroutine",
              "conditions": [
                "The background goroutine in Statements(...) runs",
                "service.CreateOplog(ctx, param) is reached"
              ],
              "implementation": "go service.CreateOplog(ctx, entity.SqlEditorOplog{EventType: exec_sql, ...}) -> repository.CreateOplog -> DB.Table(\"sql_editor_oplog\").Save(&param)"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlWithSession",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "StatementParam JSON binds successfully",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while computing the user's row limit",
              "conditions": [
                "ShowSettingsLimit(...) is reached"
              ],
              "implementation": "service.Statements -> ShowSettingsLimit -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlWithSession",
              "trigger": "Execute the user's SQL in an existing session with the user-specific row limit",
              "conditions": [
                "service.Statements(...) is reached"
              ],
              "implementation": "service.Statements -> grpc.ExecSqlWithSession(ctx, &dataapi.BasicEndpointReq{SessionId: ..., Credential: AUTH0, Source: \"chat2query-console\"})"
            }
          ]
        },
        {
          "name": "audit-log-sdk",
          "target_interface": "auditlog.EventConsoleQuerySQLFromChat2Query",
          "operation_type": "audit_submit",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "Always after service.Statements(...) returns"
          ],
          "operations": [
            {
              "operation": "SUBMIT EVENT",
              "trigger": "Submit the audit event describing SQL execution from the chat2query console",
              "conditions": [
                "Always after res, err := service.Statements(...)"
              ],
              "implementation": "auditlog.NewEvent(ctx, auditlog.EventConsoleQuerySQLFromChat2Query).ParseGIN(c)...Submit()"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/dbs/:db_name/:table_name/meta": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name and table_name path params are non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Query information_schema.columns for the requested table",
              "conditions": [
                "service.ShowTableMeta(...) is reached"
              ],
              "implementation": "service.ShowTableMeta -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Database: dbName, Sql: information_schema.columns query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/dbs/:db_name/:table_name/exist": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.CreateSession + ExecSqlWithSession",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name and table_name path params are non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC CreateSession",
              "trigger": "Create a temporary session on the requested database before checking existence",
              "conditions": [
                "service.IsDBTableExist(...) is reached"
              ],
              "implementation": "service.IsDBTableExist -> CreateSession -> grpc.CreateSession(ctx, &dataapi.CreateSessionReq{Database: dbName, Credential: AUTH0})"
            },
            {
              "operation": "gRPC ExecSqlWithSession",
              "trigger": "Run count(*) against information_schema.columns using the temporary session",
              "conditions": [
                "CreateSession succeeded"
              ],
              "implementation": "service.IsDBTableExist -> grpc.ExecSqlWithSession(ctx, &dataapi.BasicEndpointReq{SessionId: sessionId, Sql: count query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sqlfiles": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "SQLFileReq JSON binds successfully"
          ],
          "operations": [
            {
              "operation": "INSERT",
              "trigger": "Persist the new SQL file row",
              "conditions": [
                "service.CreateSQLFile(ctx, createdBy, createEntity) is reached"
              ],
              "implementation": "service.CreateSQLFile -> repository.CreateSQLFile -> DB.Table(\"sql_editor_files\").Save(&param)"
            }
          ]
        }
      },
      "services": [
        {
          "name": "audit-log-sdk",
          "target_interface": "auditlog.EventCreateSQLFileFromChat2Query",
          "operation_type": "audit_submit",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "Always after CreateSQLFile finishes"
          ],
          "operations": [
            {
              "operation": "SUBMIT EVENT",
              "trigger": "Submit the audit event for SQL file creation",
              "conditions": [
                "Always after id, err := service.CreateSQLFile(...)"
              ],
              "implementation": "auditlog.NewEvent(ctx, auditlog.EventCreateSQLFileFromChat2Query).ParseGIN(c)...Submit()"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sqlfiles/:sql_file_id": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "sql_file_id parses successfully"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load the requested SQL file row scoped to created_by",
              "conditions": [
                "service.ShowSQLFile(ctx, sqlfileId, createdBy) is reached"
              ],
              "implementation": "service.ShowSQLFile -> repository.ShowSQLFile -> DB.Table(\"sql_editor_files\").Where(\"id=? and created_by=?\", ...).First(&res)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP PUT /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sqlfiles/:sql_file_id": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "sql_file_id parses successfully",
            "SQLFileReq JSON binds successfully"
          ],
          "operations": [
            {
              "operation": "UPDATE",
              "trigger": "Update the SQL file name and content when the row belongs to the current user and is not deleted",
              "conditions": [
                "service.UpdateSQLFile(ctx, updatedBy, updateEntity) is reached"
              ],
              "implementation": "service.UpdateSQLFile -> repository.UpdateSQLFile -> DB.Table(\"sql_editor_files\").Where(\"id=? and created_by=? and is_deleted=0\", ...).Updates(...)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP DELETE /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sqlfiles/:sql_file_id": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "sql_file_id parses successfully"
          ],
          "operations": [
            {
              "operation": "UPDATE",
              "trigger": "Soft-delete the SQL file by setting is_deleted=1",
              "conditions": [
                "service.DeleteSQLFile(ctx, sqlfileId, createdBy) is reached"
              ],
              "implementation": "service.DeleteSQLFile -> repository.DeleteSQLFile -> DB.Table(\"sql_editor_files\").Where(\"id=? and created_by=?\", ...).Update(\"is_deleted\", 1)"
            }
          ]
        }
      },
      "services": [
        {
          "name": "audit-log-sdk",
          "target_interface": "auditlog.EventDeleteSQLFileFromChat2Query",
          "operation_type": "audit_submit",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "Always after DeleteSQLFile finishes"
          ],
          "operations": [
            {
              "operation": "SUBMIT EVENT",
              "trigger": "Submit the audit event for SQL file deletion",
              "conditions": [
                "Always after err := service.DeleteSQLFile(...)"
              ],
              "implementation": "auditlog.NewEvent(ctx, auditlog.EventDeleteSQLFileFromChat2Query).ParseGIN(c)...Submit()"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sqlfiles": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "List the user's non-deleted SQL files for the target cluster",
              "conditions": [
                "service.ListSQLFile(ctx, clusterId, createdBy) is reached"
              ],
              "implementation": "service.ListSQLFile -> repository.ListSQLFile -> DB.Where(\"cluster_id=? and created_by=? and is_deleted=0\", ...).Order(\"created_at desc\").Find(&sqlfileEntity)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/session": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.CreateSession",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "SessionParam JSON binds successfully",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC CreateSession",
              "trigger": "Create a SQL session for the target database and cluster",
              "conditions": [
                "service.CreateSession(...) is reached"
              ],
              "implementation": "service.CreateSession -> grpc.CreateSession(ctx, &dataapi.CreateSessionReq{Database: param.Database, Credential: AUTH0, ExpireSec: EXPIRESEC})"
            }
          ]
        }
      ]
    },
    "HTTP DELETE /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/session/:session_id": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.CloseSession",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "session_id path param is present",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC CloseSession",
              "trigger": "Close the target SQL session",
              "conditions": [
                "service.CloseSession(...) is reached"
              ],
              "implementation": "service.CloseSession -> grpc.CloseSession(ctx, &dataapi.CloseSessionReq{SessionId: sessionId, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/meta": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's settings to decide whether system schemas should be filtered",
              "conditions": [
                "service.ShowClusterMeta(...) is reached"
              ],
              "implementation": "service.ShowClusterMeta -> ShowSettings -> repository.ShowUserSettings"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while loading settings",
              "conditions": [
                "ShowSettings(...) is reached"
              ],
              "implementation": "service.ShowClusterMeta -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Load the database list from information_schema.schemata",
              "conditions": [
                "Always once ShowClusterMeta reaches the dbSql query"
              ],
              "implementation": "service.ShowClusterMeta -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Sql: dbSql, Credential: AUTH0})"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Load information_schema.columns rows for all non-excluded databases",
              "conditions": [
                "dbArray is non-empty"
              ],
              "implementation": "service.ShowClusterMeta -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Sql: metaSql, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/schemas/databases": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's settings to decide which schemas should be excluded",
              "conditions": [
                "service.ListDatabases(...) is reached"
              ],
              "implementation": "service.ListDatabases -> getExcludeDBsBySettings -> ShowSettings -> repository.ShowUserSettings"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while loading settings",
              "conditions": [
                "ShowSettings(...) is reached"
              ],
              "implementation": "service.ListDatabases -> getExcludeDBsBySettings -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Load databases from information_schema.schemata with the computed exclusion list",
              "conditions": [
                "excludeDBs computed successfully"
              ],
              "implementation": "service.ListDatabases -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Sql: schemata query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/schemas/databases/:db_name/tables": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name path param is non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's settings to decide which schemas should be excluded",
              "conditions": [
                "service.ListTables(...) is reached"
              ],
              "implementation": "service.ListTables -> getExcludeDBsBySettings -> ShowSettings -> repository.ShowUserSettings"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name path param is non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while loading settings",
              "conditions": [
                "ShowSettings(...) is reached"
              ],
              "implementation": "service.ListTables -> getExcludeDBsBySettings -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Load tables from information_schema.tables for the requested database",
              "conditions": [
                "db_name is not in the excluded schema list"
              ],
              "implementation": "service.ListTables -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Database: dbName, Sql: tables query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/schemas/databases/:db_name/tables/:table_name/columns": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name and table_name path params are non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's settings to decide which schemas should be excluded",
              "conditions": [
                "service.ListColumns(...) is reached"
              ],
              "implementation": "service.ListColumns -> getExcludeDBsBySettings -> ShowSettings -> repository.ShowUserSettings"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "db_name and table_name path params are non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while loading settings",
              "conditions": [
                "ShowSettings(...) is reached"
              ],
              "implementation": "service.ListColumns -> getExcludeDBsBySettings -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Load column definitions from information_schema.columns for the requested table",
              "conditions": [
                "db_name is not in the excluded schema list"
              ],
              "implementation": "service.ListColumns -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Database: dbName, Sql: columns query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/schemas/search": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "type query is valid and keyword is non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "SELECT OR INSERT DEFAULT",
              "trigger": "Load the user's settings to decide which schemas should be excluded",
              "conditions": [
                "service.SearchSchemas(...) is reached"
              ],
              "implementation": "service.SearchSchemas -> getExcludeDBsBySettings -> ShowSettings -> repository.ShowUserSettings"
            }
          ]
        }
      },
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + ExecSqlDirectly",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware",
            "type query is valid and keyword is non-empty",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Resolve whether the project's chat2data dataapp is enabled while loading settings",
              "conditions": [
                "ShowSettings(...) is reached"
              ],
              "implementation": "service.SearchSchemas -> getExcludeDBsBySettings -> ShowSettings -> ShowDataAppSettings -> grpc.ListDataApp(ctx, req)"
            },
            {
              "operation": "gRPC ExecSqlDirectly",
              "trigger": "Search databases, tables, or columns from information_schema based on the request type",
              "conditions": [
                "dto.SchemaSearchTypeDatabase uses schemata query",
                "dto.SchemaSearchTypeTable uses tables query",
                "dto.SchemaSearchTypeColumn uses columns query"
              ],
              "implementation": "service.SearchSchemas -> grpc.ExecSqlDirectly(ctx, &dataapi.BasicEndpointReq{Sql: type-specific search query, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/sample/initialize": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ExecSqlWithSession",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "Auth0 token is present in context"
          ],
          "operations": [
            {
              "operation": "gRPC ExecSqlWithSession",
              "trigger": "Create the fortune500 database/table and bulk-insert the embedded sample dataset",
              "conditions": [
                "Always once service.SampleDataInitialize(...) is reached"
              ],
              "implementation": "service.SampleDataInitialize -> grpc.ExecSqlWithSession(ctx, &dataapi.BasicEndpointReq{Sql: \"create database fortune500;use fortune500;\" + Fortune500DDL + Fortune500Data, Credential: AUTH0})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/status": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.GetClusterStatus",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth and RBAC middleware",
            "cluster_ids query param is present and every id parses successfully"
          ],
          "operations": [
            {
              "operation": "gRPC GetClusterStatus",
              "trigger": "Load link-status and dedicated flags for the requested clusters",
              "conditions": [
                "service.GetClusterStatus(ctx, clusterIDs) is reached"
              ],
              "implementation": "service.GetClusterStatus -> grpc.GetClusterStatus(ctx, &dataapi.GetClusterStatusReq{ClusterIds: clusterIDs})"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/users": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth and RBAC middleware"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load the current user's sqleditor profile row",
              "conditions": [
                "service.ShowUserInfo(createdBy) is reached"
              ],
              "implementation": "service.ShowUserInfo -> repository.ShowUserInfo -> DB.Table(\"sql_editor_user\").Where(\"created_by=?\", createdBy).Find(&res)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP PUT /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/users": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, and request-size middleware",
            "request body binds into map[string]interface{}"
          ],
          "operations": [
            {
              "operation": "UPSERT",
              "trigger": "Upsert the current user's sqleditor profile row",
              "conditions": [
                "service.UpdateUserInfo(param) is reached"
              ],
              "implementation": "service.UpdateUserInfo -> repository.UpdateUserInfo -> DB.Table(\"sql_editor_user\").Clauses(OnConflict...).Create(&param)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP PUT /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/settings": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.CreateDataApp + ListDataApp + DeleteDataApp",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and request-size middleware",
            "DataAppSettingsFormat JSON binds successfully"
          ],
          "operations": [
            {
              "operation": "gRPC CreateDataApp",
              "trigger": "Enable the chat2data dataapp for the project",
              "conditions": [
                "param.EnableDataAPI == true"
              ],
              "implementation": "service.UpdateDataAppSettings -> grpc.CreateDataApp(ctx, &dataapi.CreateDataAppReq{AppType: \"chat2query\", ...})"
            },
            {
              "operation": "gRPC ListDataApp",
              "trigger": "List existing chat2query dataapps before disabling them",
              "conditions": [
                "param.EnableDataAPI == false"
              ],
              "implementation": "service.UpdateDataAppSettings -> grpc.ListDataApp(ctx, &dataapi.ListDataAppReq{ProjectId: ..., AppTypes: [\"chat2query\"]})"
            },
            {
              "operation": "gRPC DeleteDataApp",
              "trigger": "Delete each existing chat2query dataapp for the project",
              "conditions": [
                "param.EnableDataAPI == false",
                "grpc.ListDataApp(...) returned one or more app ids"
              ],
              "implementation": "service.UpdateDataAppSettings -> loop appList.AppList -> grpc.DeleteDataApp(ctx, &dataapi.DeleteDataAppReq{AppId: ..., Operator: createdBy})"
            }
          ]
        }
      ]
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/oplog": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, request-size, and dedicated-cluster middleware",
            "SqlEditorOplogParam JSON binds successfully",
            "param.EventType is valid",
            "param.EventType is sql_accept or gen_sql because other event types return early without persisting"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Look up the earlier gen_sql oplog when the service layer needs to enrich non-gen_sql events",
              "conditions": [
                "service.CreateOplog(...) is reached",
                "param.EventType != gen_sql",
                "param.Chat2QuerySId != \"\""
              ],
              "implementation": "service.CreateOplog -> ShowOplog -> repository.ShowOplog -> DB.Table(\"sql_editor_oplog\").Where(\"chat2query_sid=? AND event_type=?\", ...).First(&res)"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the SQL editor oplog entry",
              "conditions": [
                "service.CreateOplog(ctx, param) is reached"
              ],
              "implementation": "service.CreateOplog -> repository.CreateOplog -> DB.Table(\"sql_editor_oplog\").Save(&param)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/dataapi/sample": {
      "infrastructure": {},
      "services": [
        {
          "name": "dataservices-dataapi",
          "target_interface": "DataAPIService.ListDataApp + EndpointCodeExample",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/dataservices",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware"
          ],
          "operations": [
            {
              "operation": "gRPC ListDataApp",
              "trigger": "Check whether the project's chat2data dataapp is enabled",
              "conditions": [
                "service.ShowDataAppSettings(ctx, projectId) is reached"
              ],
              "implementation": "service.ShowDataAppSettings -> grpc.ListDataApp(ctx, &dataapi.ListDataAppReq{ProjectId: ..., AppTypes: [\"chat2query\"]})"
            },
            {
              "operation": "gRPC EndpointCodeExample",
              "trigger": "Fetch the sample curl/code example for the enabled chat2data endpoint",
              "conditions": [
                "settings.EnableDataAPI == true"
              ],
              "implementation": "service.ShowChat2DataURL -> grpc.EndpointCodeExample(ctx, &dataapi.EndpointCodeExampleReq{ProjectId: ..., ClusterId: ..., EndpointType: \"chat2data\"})"
            }
          ]
        }
      ]
    },
    "HTTP POST /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/bot": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "The request passes auth, RBAC, request-size, and bot-body-size middleware",
            "InteractRequest binds successfully",
            "service.CheckInteractReqeustValid(req) succeeds"
          ],
          "operations": [
            {
              "operation": "INSERT",
              "trigger": "Persist the generated gen_sql oplog asynchronously after the AI call returns",
              "conditions": [
                "The background goroutine in service.InteractBot(...) runs",
                "service.CreateOplog(ctx, oplogParam) is reached"
              ],
              "implementation": "service.InteractBot -> go CreateOplog(ctx, oplogParam{EventType: gen_sql, ...}) -> repository.CreateOplog"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the synthetic sql_accept oplog for successful non-chat2sql bot types",
              "conditions": [
                "botType != \"chat2sql\"",
                "status == 1 in service.InteractBot's background goroutine"
              ],
              "implementation": "service.InteractBot -> oplogParam.EventType = sql_accept; CreateOplog(ctx, oplogParam) -> repository.CreateOplog"
            }
          ]
        }
      },
      "services": [
        {
          "name": "aipower",
          "target_interface": "ChatBotService.ChatBot",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/aipower",
          "conditions": [
            "The request passes auth, RBAC, request-size, and bot-body-size middleware",
            "InteractRequest binds successfully",
            "service.CheckInteractReqeustValid(req) succeeds"
          ],
          "operations": [
            {
              "operation": "gRPC ChatBot",
              "trigger": "Generate SQL or chat content from the user's question",
              "conditions": [
                "Always once service.InteractBot(ctx, req, createdBy) is reached"
              ],
              "implementation": "service.InteractBot -> grpc.ChatBot(ctx, botReq)"
            }
          ]
        },
        {
          "name": "eda-service",
          "target_interface": "POST /inner/eda/api/v1/eda/orgs/{org_id}/projects/{project_id}/chat2sql",
          "operation_type": "http_post",
          "target_repo": "tidbcloud/eda",
          "conditions": [
            "The request passes auth and RBAC middleware",
            "The fire-and-forget goroutine is scheduled before the AI response returns"
          ],
          "operations": [
            {
              "operation": "HTTP POST",
              "trigger": "Send the chat2sql evaluation request to EDA asynchronously",
              "conditions": [
                "Always once InteractBot reaches go eda.EDAChat2SQL(...)"
              ],
              "implementation": "sqleditor.InteractBot -> go eda.EDAChat2SQL(...) -> httpclient.RequestWithHeader(ctx, http.MethodPost, url, nil, &header, payload)"
            }
          ]
        },
        {
          "name": "audit-log-sdk",
          "target_interface": "auditlog.EventConsoleChat2SQLFromChat2Query",
          "operation_type": "audit_submit",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "Always after rsp, err := service.InteractBot(...)"
          ],
          "operations": [
            {
              "operation": "SUBMIT EVENT",
              "trigger": "Submit the audit event for AI interaction in the chat2query console",
              "conditions": [
                "Always after service.InteractBot(...) returns"
              ],
              "implementation": "auditlog.NewEvent(ctx, auditlog.EventConsoleChat2SQLFromChat2Query).ParseGIN(c)...Submit()"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/clusters/:cluster_id/enter/audit": {
      "infrastructure": {},
      "services": [
        {
          "name": "audit-log-sdk",
          "target_interface": "auditlog.EventEnterChat2Query",
          "operation_type": "audit_submit",
          "target_repo": "tidbcloud/tiinf",
          "conditions": [
            "The request passes auth, RBAC, and dedicated-cluster middleware"
          ],
          "operations": [
            {
              "operation": "SUBMIT EVENT",
              "trigger": "Submit the audit event for entering chat2query",
              "conditions": [
                "Always once AuditLog4EnterChat2Query reaches auditlog.NewEvent(...)"
              ],
              "implementation": "auditlog.NewEvent(ctx, auditlog.EventEnterChat2Query).ParseGIN(c)...Submit()"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/permission/entry": {
      "infrastructure": {},
      "services": [
        {
          "name": "core-svc",
          "target_interface": "CoreService.ListClusters",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/core-svc",
          "conditions": [
            "The request passes auth and RBAC middleware",
            "cluster_ids query param is present and every id parses successfully"
          ],
          "operations": [
            {
              "operation": "gRPC ListClusters",
              "trigger": "Fetch cluster features so the handler can decide whether delegate-user entry is supported",
              "conditions": [
                "service.ServerlessPermission2Entry(ctx, clusterIDs) is reached"
              ],
              "implementation": "service.ServerlessPermission2Entry -> grpc.GetClusterByIds(ctx, clusterIds) -> core.ListClusters(ctx, req)"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/dataapps/sqleditor/orgs/:org_id/projects/:project_id/streaming": {
      "infrastructure": {},
      "services": [
        {
          "name": "aipower",
          "target_interface": "ChatBotService.QueryCompletionByJobID",
          "operation_type": "grpc_unary",
          "target_repo": "tidbcloud/aipower",
          "conditions": [
            "The request passes auth and RBAC middleware",
            "QueryStreamResultReq binds successfully from the query string",
            "req.BotType is one of chat2sql, data2columnMatching, or chat2question"
          ],
          "operations": [
            {
              "operation": "gRPC QueryCompletionByJobID",
              "trigger": "Fetch the stored streaming completion result for a previous async AI request",
              "conditions": [
                "req.BotType is allowed by streamEnabledAIModels"
              ],
              "implementation": "sqleditor.QueryStreamResultByJobID -> grpc.QueryStreamResponse(ctx, &req)"
            }
          ]
        }
      ]
    },
    "HTTP POST /inner/sqleditor/oplog": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "InnerSqlEditorOplogParam JSON binds successfully",
            "param.EventType is valid"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Look up the earlier gen_sql oplog when the service layer needs to enrich non-gen_sql events",
              "conditions": [
                "param.CreatedBy != \"internal\"",
                "param.EventType != gen_sql",
                "param.Chat2QuerySId != \"\""
              ],
              "implementation": "service.CreateOplog -> ShowOplog -> repository.ShowOplog"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the inner SQL editor oplog entry unless the caller is the synthetic internal user",
              "conditions": [
                "param.CreatedBy != \"internal\""
              ],
              "implementation": "sqleditor.InnerCreateOplog -> service.CreateOplog -> repository.CreateOplog -> DB.Table(\"sql_editor_oplog\").Save(&param)"
            }
          ]
        }
      },
      "services": []
    },
    "Runtime SqlEditorEDAProxyHTTP.ProxyRequests": {
      "infrastructure": {},
      "services": [
        {
          "name": "eda-service",
          "target_interface": "HTTP proxy target under /inner/eda",
          "operation_type": "http_proxy",
          "target_repo": "tidbcloud/eda",
          "conditions": [
            "The request passes auth and RBAC middleware",
            "A current user exists in context",
            "org_id and project_id path params parse successfully"
          ],
          "operations": [
            {
              "operation": "HTTP REQUEST",
              "trigger": "Forward the original request method, query string, selected headers, and optional JSON body to the EDA service",
              "conditions": [
                "Request body is either empty or valid JSON if present"
              ],
              "implementation": "eda.EDAProxy -> httpclient.RequestWithHeader(ctx, method, url, &queryString, &header, payload)"
            }
          ]
        }
      ]
    },
    "HTTP GET /metrics": {
      "infrastructure": {},
      "services": []
    },
    "SqlEditorGRPC.CreateOpLog": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always once the gRPC method is invoked"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Look up the earlier gen_sql oplog when the service layer needs to enrich non-gen_sql events",
              "conditions": [
                "req.Chat2QuerySid != \"\"",
                "event type is not gen_sql after conversion to entity.SqlEditorOplog"
              ],
              "implementation": "service.CreateOplog -> ShowOplog -> repository.ShowOplog"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the gRPC-delivered SQL editor oplog entry",
              "conditions": [
                "service.CreateOplog(ctx, entity.SqlEditorOplog{...}) is reached"
              ],
              "implementation": "sqleditorGrpcService.CreateOpLog -> service.CreateOplog -> repository.CreateOplog -> DB.Table(\"sql_editor_oplog\").Save(&param)"
            }
          ]
        }
      },
      "services": []
    }
  },
  "notes": [
    "Most public sqleditor routes are gated by CheckUser, CheckRBACPermission, and, when a cluster_id path is present, CheckDedicatedClusterPermission before the handler body runs.",
    "Routing order matters in this binary: /healthz is registered before later middleware, while /inner/sqleditor/oplog is registered before CORS, auth, RBAC, request-size, and dedicated-cluster middleware are attached.",
    "The old scan flattened middleware, inner routes, metrics, and gRPC into a partial HTTP-only picture. The fresh scan keeps those runtime surfaces separate and aligns every method key with the canonical interface file."
  ]
}
