{
  "repo": "tidbcloud/debug-portal",
  "binary": "debug-portal",
  "binary_path": "cmd/main.go",
  "dependencies": {
    "Runtime DebugPortalLifecycle.Startup": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Always at process startup"
          ],
          "operations": [
            {
              "operation": "CREATE DATABASE IF NOT EXISTS",
              "trigger": "Ensure the configured database exists before opening the global pool",
              "conditions": [
                "Always"
              ],
              "implementation": "db.InitializeWithoutMigrate -> db.EnsureConnectionDatabase -> tx.Exec(\"CREATE DATABASE IF NOT EXISTS ...\")"
            },
            {
              "operation": "CONNECT",
              "trigger": "Initialize the global GORM connection pool",
              "conditions": [
                "Always"
              ],
              "implementation": "db.InitializeWithoutMigrate -> db.Connect"
            }
          ]
        }
      },
      "services": []
    },
    "Runtime DebugPortalLifecycle.BuildGRPCServer": {
      "infrastructure": {},
      "services": []
    },
    "Runtime DebugPortalLifecycle.BuildHTTPGateway": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.*",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "Register grpc-gateway handlers against the local gRPC server",
              "trigger": "Expose /debug-api/v1/* over HTTP",
              "conditions": [
                "Always"
              ],
              "implementation": "pb.RegisterCentralDebugPortalServiceHandlerFromEndpoint(context.Background(), mux, \"localhost:9191\", opts)"
            }
          ]
        }
      ]
    },
    "CentralDebugPortalService.GetOAuthConfig": {
      "infrastructure": {},
      "services": []
    },
    "CentralDebugPortalService.ExchangeOAuthToken": {
      "infrastructure": {},
      "services": [
        {
          "name": "oauth-provider",
          "target_interface": "POST token endpoint",
          "operation_type": "http_post",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "HTTP POST",
              "trigger": "Exchange the OAuth authorization code for an access token",
              "conditions": [
                "Always"
              ],
              "implementation": "session.OAuthClient.Exchange -> client.config.Exchange(ctx2, code)"
            }
          ]
        },
        {
          "name": "oauth-provider",
          "target_interface": "GET user info endpoint",
          "operation_type": "http_get",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "HTTP GET",
              "trigger": "Fetch user profile after the token exchange",
              "conditions": [
                "Always"
              ],
              "implementation": "session.OAuthClient.Exchange -> httpClient.Get(client.userInfoURL)"
            }
          ]
        }
      ]
    },
    "CentralDebugPortalService.SignOut": {
      "infrastructure": {},
      "services": []
    },
    "CentralDebugPortalService.GetBasicSession": {
      "infrastructure": {},
      "services": []
    },
    "CentralDebugPortalService.ListTenants": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "List tenants with optional filters and pagination",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "model.(*Model).ListTenants -> entity.NewTenantQuerySet(...).All(&tenants)"
            },
            {
              "operation": "SELECT",
              "trigger": "Load per-tenant discount rows while building the response payload",
              "conditions": [
                "For each tenant returned by the primary query"
              ],
              "implementation": "model.(*Model).ListTenants -> entity.NewDiscountQuerySet(tx).TenantIDEq(item.ID).All(&tenantDiscount)"
            }
          ]
        }
      },
      "services": []
    },
    "CentralDebugPortalService.GetTenantById": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load the tenant row by org_id through the shared ListTenants helper",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "model.(*Model).ListTenants(\"\", req.OrgId, \"\", nil, 0, 0) -> entity.NewTenantQuerySet(...).All(&tenants)"
            },
            {
              "operation": "SELECT",
              "trigger": "Load discount rows while materializing the tenant response",
              "conditions": [
                "If the tenant exists"
              ],
              "implementation": "model.(*Model).ListTenants -> entity.NewDiscountQuerySet(tx).TenantIDEq(item.ID).All(&tenantDiscount)"
            }
          ]
        }
      },
      "services": []
    },
    "CentralDebugPortalService.ListTenantClusters": {
      "infrastructure": {},
      "services": [
        {
          "name": "core-svc",
          "target_repo": "tidbcloud/core-svc",
          "target_interface": "CoreService.ListClusters",
          "operation_type": "grpc_unary",
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "gRPC ListClusters",
              "trigger": "Fetch the tenant's cluster page for the requested org_id",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "grpcli.ListClusters -> core.CoreServiceClient.ListClusters(ctx, listReq)"
            }
          ]
        },
        {
          "name": "core-svc",
          "target_repo": "tidbcloud/core-svc",
          "target_interface": "CoreService.CountClusters",
          "operation_type": "grpc_unary",
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "gRPC CountClusters",
              "trigger": "Fetch the total cluster count for pagination",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "grpcli.CountClusters -> core.CoreServiceClient.CountClusters(ctx, &core.CountClustersReq{Filter: filter})"
            }
          ]
        }
      ]
    },
    "CentralDebugPortalService.GetDashboardLinks": {
      "infrastructure": {
        "mysql": {
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "SELECT",
              "trigger": "Load tenant metadata needed for dashboard query parameters",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "model.(*Model).GetDashboardLinks -> entity.NewTenantQuerySet(tx).IDEq(entity.ID(tenantID)).One(&t)"
            },
            {
              "operation": "SELECT",
              "trigger": "Load cluster metadata for the dashboard link",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "model.(*Model).GetDashboardLinks -> entity.NewClusterQuerySet(tx).StatusNotIn(...).IDEq(entity.ID(clusterID)).One(&cluster)"
            }
          ]
        }
      },
      "services": [
        {
          "name": "grafana",
          "target_interface": "GET /api/search",
          "operation_type": "http_get",
          "conditions": [
            "Authenticated debug session required"
          ],
          "operations": [
            {
              "operation": "HTTP GET",
              "trigger": "Search Grafana dashboards tagged with the configured TiDB dashboard tag",
              "conditions": [
                "Always after auth"
              ],
              "implementation": "model.(*Model).GetDashboardLinks -> grafanaClient.Search(context.TODO(), params...) -> GrafanaClient.get(ctx, \"api/search\", q)"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/oauth/config": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.GetOAuthConfig",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC GetOAuthConfig call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_GetOAuthConfig_0 -> client.GetOAuthConfig"
            }
          ]
        }
      ]
    },
    "HTTP POST /debug-api/v1/oauth/exchange": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.ExchangeOAuthToken",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "grpc-gateway POST proxy",
              "trigger": "Translate the HTTP request into a local gRPC ExchangeOAuthToken call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_ExchangeOAuthToken_0 -> client.ExchangeOAuthToken"
            }
          ]
        }
      ]
    },
    "HTTP POST /debug-api/v1/auth/sign_out": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.SignOut",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie and matching x-csrf-token are required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway POST proxy",
              "trigger": "Translate the HTTP request into a local gRPC SignOut call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_SignOut_0 -> client.SignOut"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/me": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.GetBasicSession",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie is required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC GetBasicSession call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_GetBasicSession_0 -> client.GetBasicSession"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/orgs": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.ListTenants",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie is required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC ListTenants call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_ListTenants_0 -> client.ListTenants"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/orgs/{org_id}": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.GetTenantById",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie is required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC GetTenantById call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_GetTenantById_0 -> client.GetTenantById"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/orgs/{org_id}/clusters": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.ListTenantClusters",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie is required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC ListTenantClusters call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_ListTenantClusters_0 -> client.ListTenantClusters"
            }
          ]
        }
      ]
    },
    "HTTP GET /debug-api/v1/orgs/{org_id}/clusters/{cluster_id}/dashboard_links": {
      "infrastructure": {},
      "services": [
        {
          "name": "debug-portal",
          "target_repo": "tidbcloud/debug-portal",
          "target_interface": "CentralDebugPortalService.GetDashboardLinks",
          "operation_type": "grpc_gateway_proxy",
          "conditions": [
            "Valid debug session cookie is required"
          ],
          "operations": [
            {
              "operation": "grpc-gateway GET proxy",
              "trigger": "Translate the HTTP request into a local gRPC GetDashboardLinks call",
              "conditions": [
                "Always"
              ],
              "implementation": "service.pb.gw.go request_CentralDebugPortalService_GetDashboardLinks_0 -> client.GetDashboardLinks"
            }
          ]
        }
      ]
    }
  },
  "notes": [
    "The HTTP gateway is a thin grpc-gateway proxy layer; downstream service calls occur in the gRPC handlers rather than in the HTTP adapter itself.",
    "GetOAuthConfig, SignOut, and GetBasicSession are local-only operations aside from session cookie/header manipulation.",
    "ListTenants and GetTenantById both reuse model.ListTenants, so the org-by-id path still performs the shared tenant query and per-tenant discount lookup."
  ]
}
