{
  "repo": "tidbcloud/api-gateway",
  "binary": "server",
  "binary_path": "ui/cmd/server/main.go",
  "dependencies": {
    "APIGatewayLifecycle.ParseFlags": {
      "infrastructure": {},
      "services": []
    },
    "APIGatewayLifecycle.ResolveKubeConfig": {
      "infrastructure": {
        "filesystem": {
          "conditions": [
            "Only on the out-of-cluster fallback path"
          ],
          "operations": [
            {
              "operation": "READ FILE",
              "trigger": "Load kubeconfig from the explicit or default path when in-cluster config is unavailable",
              "conditions": [
                "rest.InClusterConfig() returned an error",
                "clientcmd.BuildConfigFromFlags(masterURL, kubeconfig) is reached"
              ],
              "implementation": "clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)"
            }
          ]
        }
      },
      "services": []
    },
    "APIGatewayLifecycle.InitializeDatabase": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always during process startup because dao.init() runs before main()"
          ],
          "operations": [
            {
              "operation": "OPEN DB HANDLE",
              "trigger": "Create the shared GORM handle from the hard-coded DSN",
              "conditions": [
                "Always"
              ],
              "implementation": "dao.init() -> gorm.Open(mysql.Open(\"root:root@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local\"), &gorm.Config{})"
            }
          ]
        }
      },
      "services": []
    },
    "APIGatewayLifecycle.InitializeController": {
      "infrastructure": {},
      "services": [
        {
          "name": "kubernetes-control-plane",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "CoreV1 + NetworkingV1 clientset and informer factory",
          "operation_type": "kubernetes_connect",
          "conditions": [
            "Always after a rest.Config has been resolved"
          ],
          "operations": [
            {
              "operation": "CREATE CLIENTSET",
              "trigger": "Build the kubernetes client used later for ingress deployment",
              "conditions": [
                "cfg != nil"
              ],
              "implementation": "controller.Init(cfg) -> kubernetes.NewForConfig(cfg)"
            },
            {
              "operation": "START INFORMERS",
              "trigger": "Start service and namespace informers used by the API cache readers",
              "conditions": [
                "clientset initialization succeeded"
              ],
              "implementation": "informers.NewSharedInformerFactory(kubeClient, time.Minute*10); kubeInformerFactory.Start(wait.NeverStop)"
            },
            {
              "operation": "WAIT FOR CACHE SYNC",
              "trigger": "Block startup until namespace and service caches are synchronized",
              "conditions": [
                "informers were started"
              ],
              "implementation": "kubeInformerFactory.WaitForCacheSync(wait.NeverStop)"
            }
          ]
        }
      ]
    },
    "APIGatewayLifecycle.StartHTTPServer": {
      "infrastructure": {},
      "services": []
    },
    "Runtime APIGatewayStaticHTTP.ServeFrontend": {
      "infrastructure": {
        "filesystem": {
          "conditions": [
            "Only when no explicit API route matched and the NoRoute handler is reached"
          ],
          "operations": [
            {
              "operation": "READ FILE",
              "trigger": "Serve frontend assets or index pages from the frontend/ directory",
              "conditions": [
                "The request path maps to an existing file under frontend/"
              ],
              "implementation": "r.NoRoute(func(c *gin.Context) { c.File(path.Join(\"frontend\", c.Request.URL.Path)) })"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP POST /api/v1/route": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Only after request binding succeeds and route validation passes"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load all active routes for the requested host before validating path-to-testcase coverage",
              "conditions": [
                "ctx.Bind(param) succeeded"
              ],
              "implementation": "dao.ListRoutesByHost(param.Host)"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist the new active route row after validation passes",
              "conditions": [
                "routeModels.Validate() returned nil",
                "strconv.Atoi(param.ServicePort) inside dao.CreateRoute succeeded"
              ],
              "implementation": "dao.CreateRoute(param.Host, param.Path, param.Namespace, param.ServiceName, param.ServicePort, strings.Join(param.TestCases, \",\"))"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist a new version row with the generated ingress YAML after ingress deployment succeeds",
              "conditions": [
                "controller.DeployIngresses(ingresses) returned nil"
              ],
              "implementation": "dao.CreateNewVersion(param.Host, string(yml))"
            }
          ]
        }
      },
      "services": [
        {
          "name": "kubernetes-networking",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "NetworkingV1.Ingresses.Create/Update",
          "operation_type": "kubernetes_write",
          "conditions": [
            "Only after route validation passed and the route row was inserted successfully"
          ],
          "operations": [
            {
              "operation": "CREATE OR UPDATE INGRESS",
              "trigger": "Deploy the generated ingress objects for the host and namespace fan-out",
              "conditions": [
                "dao.CreateRoute(...) returned nil"
              ],
              "implementation": "controller.BuildIngresses(routeModels); controller.DeployIngresses(ingresses) -> clientset.NetworkingV1().Ingresses(namespace).Create(...); on Create error: Update(...)"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/routes": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load all active routes ordered by descending id",
              "conditions": [
                "Always"
              ],
              "implementation": "dao.ListRoutes() -> db.Where(\"status = ?\", true).Order(\"id desc\").Find(&routes)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP GET /api/v1/route/:routeID": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Only after routeID parses as an integer"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load the requested route row",
              "conditions": [
                "strconv.Atoi(ctx.Param(\"routeID\")) succeeded"
              ],
              "implementation": "dao.GetRoute(id) -> db.First(route, id)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP POST /api/v1/route/:routeID": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Only after routeID parsing, request binding, and route validation succeed"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load all active routes for the host before revalidating overlap; the current route id is skipped locally during validation",
              "conditions": [
                "strconv.Atoi(ctx.Param(\"routeID\")) succeeded",
                "ctx.Bind(param) succeeded"
              ],
              "implementation": "dao.ListRoutesByHost(param.Host)"
            },
            {
              "operation": "SELECT",
              "trigger": "Load the existing route row before overwriting its fields",
              "conditions": [
                "routeModels.Validate() returned nil",
                "strconv.Atoi(param.ServicePort) inside dao.UpdateRoute succeeded"
              ],
              "implementation": "dao.UpdateRoute(id, ...) -> db.First(route, id)"
            },
            {
              "operation": "UPDATE",
              "trigger": "Persist the updated route row after validation passes",
              "conditions": [
                "db.First(route, id) returned nil"
              ],
              "implementation": "dao.UpdateRoute(id, ...) -> db.Save(route)"
            },
            {
              "operation": "INSERT",
              "trigger": "Persist a new version row with the generated ingress YAML after redeployment succeeds",
              "conditions": [
                "controller.DeployIngresses(ingresses) returned nil"
              ],
              "implementation": "dao.CreateNewVersion(param.Host, string(yml))"
            }
          ]
        }
      },
      "services": [
        {
          "name": "kubernetes-networking",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "NetworkingV1.Ingresses.Create/Update",
          "operation_type": "kubernetes_write",
          "conditions": [
            "Only after the updated route row was written successfully"
          ],
          "operations": [
            {
              "operation": "CREATE OR UPDATE INGRESS",
              "trigger": "Redeploy generated ingress objects after the route change",
              "conditions": [
                "dao.UpdateRoute(...) returned nil"
              ],
              "implementation": "controller.BuildIngresses(routeModels); controller.DeployIngresses(ingresses) -> clientset.NetworkingV1().Ingresses(namespace).Create(...); on Create error: Update(...)"
            }
          ]
        }
      ]
    },
    "HTTP DELETE /api/v1/route/:routeID": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Only after routeID parses as an integer"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load the existing route row before soft deletion",
              "conditions": [
                "strconv.Atoi(ctx.Param(\"routeID\")) succeeded"
              ],
              "implementation": "dao.DeleteRoute(id) -> db.First(route, id)"
            },
            {
              "operation": "UPDATE",
              "trigger": "Soft delete the route by setting status=false",
              "conditions": [
                "db.First(route, id) returned nil"
              ],
              "implementation": "dao.DeleteRoute(id) -> route.Status = false; db.Save(route)"
            }
          ]
        }
      },
      "services": []
    },
    "HTTP GET /api/v1/namespaces": {
      "infrastructure": {},
      "services": [
        {
          "name": "kubernetes-namespace-cache",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "Namespace informer cache",
          "operation_type": "kubernetes_cache_read",
          "conditions": [
            "Only after controller.Init has completed cache sync"
          ],
          "operations": [
            {
              "operation": "LIST FROM CACHE",
              "trigger": "List namespace names from the informer-backed lister",
              "conditions": [
                "controllerObj != nil",
                "namespace cache was synced during startup"
              ],
              "implementation": "controller.ListNamespaceNames() -> controllerObj.namespaceLister.List(labels.NewSelector())"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/namespace/:namespace/services": {
      "infrastructure": {},
      "services": [
        {
          "name": "kubernetes-service-cache",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "Service informer cache",
          "operation_type": "kubernetes_cache_read",
          "conditions": [
            "Only after controller.Init has completed cache sync"
          ],
          "operations": [
            {
              "operation": "LIST FROM CACHE",
              "trigger": "List all services in the requested namespace from the informer-backed lister",
              "conditions": [
                "namespace path param is provided"
              ],
              "implementation": "controller.ListNodePortServiceNames(namespace) -> controllerObj.serviceLister.Services(namespace).List(labels.NewSelector())"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/namespace/:namespace/service/:service/ports": {
      "infrastructure": {},
      "services": [
        {
          "name": "kubernetes-service-cache",
          "target_repo": "kubernetes/kubernetes",
          "target_interface": "Service informer cache",
          "operation_type": "kubernetes_cache_read",
          "conditions": [
            "Only after controller.Init has completed cache sync"
          ],
          "operations": [
            {
              "operation": "LIST FROM CACHE",
              "trigger": "List services in the namespace, then keep only the one whose name matches the requested service",
              "conditions": [
                "namespace path param is provided",
                "service path param is provided"
              ],
              "implementation": "controller.ListServicePorts(namespace, serviceName) -> controllerObj.serviceLister.Services(namespace).List(labels.NewSelector())"
            }
          ]
        }
      ]
    },
    "HTTP GET /api/v1/versions": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load version history rows ordered by descending id",
              "conditions": [
                "Always"
              ],
              "implementation": "dao.ListVersions() -> db.Order(\"id desc\").Find(&versions)"
            }
          ]
        }
      },
      "services": []
    }
  }
}
