Bug: [FEATURE] Add support for health check endpoint and setting up configs in v2



### Feature Description

v2 application needs to have an endpoint for setting up configs and health check endpoint.

### Possible Implementation

Replicate the v1 implementation

### Have you spent some time checking if this feature request has been raised before?

- [x] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [x] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/api_models/src/health_check.rs b/crates/api_models/src/health_check.rs
index a6261da1be0..e782a3a100c 100644
--- a/crates/api_models/src/health_check.rs
+++ b/crates/api_models/src/health_check.rs
@@ -14,6 +14,7 @@ pub struct RouterHealthCheckResponse {
     pub grpc_health_check: HealthCheckMap,
     #[cfg(feature = "dynamic_routing")]
     pub decision_engine: bool,
+    pub unified_connector_service: Option<bool>,
 }
 
 impl common_utils::events::ApiEventMetric for RouterHealthCheckResponse {}
diff --git a/crates/router/src/core/health_check.rs b/crates/router/src/core/health_check.rs
index 7bc65e4d0e4..5df265ec4ee 100644
--- a/crates/router/src/core/health_check.rs
+++ b/crates/router/src/core/health_check.rs
@@ -40,6 +40,10 @@ pub trait HealthCheckInterface {
     async fn health_check_decision_engine(
         &self,
     ) -> CustomResult<HealthState, errors::HealthCheckDecisionEngineError>;
+
+    async fn health_check_unified_connector_service(
+        &self,
+    ) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError>;
 }
 
 #[async_trait::async_trait]
@@ -210,4 +214,19 @@ impl HealthCheckInterface for app::SessionState {
             Ok(HealthState::NotApplicable)
         }
     }
+
+    async fn health_check_unified_connector_service(
+        &self,
+    ) -> CustomResult<HealthState, errors::HealthCheckUnifiedConnectorServiceError> {
+        if let Some(_ucs_client) = &self.grpc_client.unified_connector_service_client {
+            // For now, we'll just check if the client exists and is configured
+            // In the future, this could be enhanced to make an actual health check call
+            // to the unified connector service if it supports health check endpoints
+            logger::debug!("Unified Connector Service client is configured and available");
+            Ok(HealthState::Running)
+        } else {
+            logger::debug!("Unified Connector Service client not configured");
+            Ok(HealthState::NotApplicable)
+        }
+    }
 }
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 9584a9af160..08a0d0f386e 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -557,6 +557,7 @@ impl AppState {
 
 pub struct Health;
 
+#[cfg(feature = "v1")]
 impl Health {
     pub fn server(state: AppState) -> Scope {
         web::scope("health")
@@ -566,6 +567,16 @@ impl Health {
     }
 }
 
+#[cfg(feature = "v2")]
+impl Health {
+    pub fn server(state: AppState) -> Scope {
+        web::scope("/v2/health")
+            .app_data(web::Data::new(state))
+            .service(web::resource("").route(web::get().to(health)))
+            .service(web::resource("/ready").route(web::get().to(deep_health_check)))
+    }
+}
+
 #[cfg(feature = "dummy_connector")]
 pub struct DummyConnector;
 
@@ -1852,7 +1863,7 @@ impl Webhooks {
 
 pub struct Configs;
 
-#[cfg(any(feature = "olap", feature = "oltp"))]
+#[cfg(all(feature = "v1", any(feature = "olap", feature = "oltp")))]
 impl Configs {
     pub fn server(config: AppState) -> Scope {
         web::scope("/configs")
@@ -1867,6 +1878,21 @@ impl Configs {
     }
 }
 
+#[cfg(all(feature = "v2", any(feature = "olap", feature = "oltp")))]
+impl Configs {
+    pub fn server(config: AppState) -> Scope {
+        web::scope("/v2/configs")
+            .app_data(web::Data::new(config))
+            .service(web::resource("/").route(web::post().to(config_key_create)))
+            .service(
+                web::resource("/{key}")
+                    .route(web::get().to(config_key_retrieve))
+                    .route(web::post().to(config_key_update))
+                    .route(web::delete().to(config_key_delete)),
+            )
+    }
+}
+
 pub struct ApplePayCertificatesMigration;
 
 #[cfg(all(feature = "olap", feature = "v1"))]
diff --git a/crates/router/src/routes/configs.rs b/crates/router/src/routes/configs.rs
index 74b9cd73b1e..1425fda32ba 100644
--- a/crates/router/src/routes/configs.rs
+++ b/crates/router/src/routes/configs.rs
@@ -8,6 +8,11 @@ use crate::{
     types::api as api_types,
 };
 
+#[cfg(feature = "v1")]
+const ADMIN_API_AUTH: auth::AdminApiAuth = auth::AdminApiAuth;
+#[cfg(feature = "v2")]
+const ADMIN_API_AUTH: auth::V2AdminApiAuth = auth::V2AdminApiAuth;
+
 #[instrument(skip_all, fields(flow = ?Flow::CreateConfigKey))]
 pub async fn config_key_create(
     state: web::Data<AppState>,
@@ -23,7 +28,7 @@ pub async fn config_key_create(
         &req,
         payload,
         |state, _, data, _| configs::set_config(state, data),
-        &auth::AdminApiAuth,
+        &ADMIN_API_AUTH,
         api_locking::LockAction::NotApplicable,
     )
     .await
@@ -43,7 +48,7 @@ pub async fn config_key_retrieve(
         &req,
         &key,
         |state, _, key, _| configs::read_config(state, key),
-        &auth::AdminApiAuth,
+        &ADMIN_API_AUTH,
         api_locking::LockAction::NotApplicable,
     )
     .await
@@ -66,7 +71,7 @@ pub async fn config_key_update(
         &req,
         &payload,
         |state, _, payload, _| configs::update_config(state, payload),
-        &auth::AdminApiAuth,
+        &ADMIN_API_AUTH,
         api_locking::LockAction::NotApplicable,
     )
     .await
@@ -87,7 +92,7 @@ pub async fn config_key_delete(
         &req,
         key,
         |state, _, key, _| configs::config_delete(state, key),
-        &auth::AdminApiAuth,
+        &ADMIN_API_AUTH,
         api_locking::LockAction::NotApplicable,
     )
     .await
diff --git a/crates/router/src/routes/health.rs b/crates/router/src/routes/health.rs
index f2ed05030da..b7818c0db5b 100644
--- a/crates/router/src/routes/health.rs
+++ b/crates/router/src/routes/health.rs
@@ -150,6 +150,21 @@ async fn deep_health_check_func(
 
     logger::debug!("Outgoing Request health check end");
 
+    logger::debug!("Unified Connector Service health check begin");
+
+    let unified_connector_service_status = state
+        .health_check_unified_connector_service()
+        .await
+        .map_err(|error| {
+            let message = error.to_string();
+            error.change_context(errors::ApiErrorResponse::HealthCheckError {
+                component: "Unified Connector Service",
+                message,
+            })
+        })?;
+
+    logger::debug!("Unified Connector Service health check end");
+
     let response = RouterHealthCheckResponse {
         database: db_status.into(),
         redis: redis_status.into(),
@@ -163,6 +178,7 @@ async fn deep_health_check_func(
         grpc_health_check,
         #[cfg(feature = "dynamic_routing")]
         decision_engine: decision_engine_health_check.into(),
+        unified_connector_service: unified_connector_service_status.into(),
     };
 
     Ok(api::ApplicationResponse::Json(response))
diff --git a/crates/storage_impl/src/errors.rs b/crates/storage_impl/src/errors.rs
index 89326d9a71c..a2b4dad779b 100644
--- a/crates/storage_impl/src/errors.rs
+++ b/crates/storage_impl/src/errors.rs
@@ -294,3 +294,9 @@ pub enum HealthCheckDecisionEngineError {
     #[error("Failed to establish Decision Engine connection")]
     FailedToCallDecisionEngineService,
 }
+
+#[derive(Debug, Clone, thiserror::Error)]
+pub enum HealthCheckUnifiedConnectorServiceError {
+    #[error("Failed to establish Unified Connector Service connection")]
+    FailedToCallUnifiedConnectorService,
+}

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
Introduced` /v2/configs` and `/v2/health` endpoints and for v2

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
introduced configs and health endpoints for v2


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Manual.

1. Hit V2 health endpoint.
```
curl --location '{{base_url}}/v2/health/ready' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: public' \
--data ''
```
response:
```
{
    "database": true,
    "redis": true,
    "analytics": true,
    "opensearch": false,
    "outgoing_request": true,
    "unified_connector_service": true
}
```

2. Create a test v2 config
```
curl --location '{{baseUrl}}/v2/configs/' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: public' \
--header 'authorization: admin-api-key=test_admin' \
--data '
{
    "key": "test_v2_config_1",
    "value": "true"
}
'
```

2. Retrive the test v2 config
```
curl --location '{{baseUrl}}/v2/configs/test_v2_config_1' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: public' \
--header 'authorization: admin-api-key=test_admin' \
--data ''
```

Response for 2 and 3:
```
{
    "key": "test_v2_config_1",
    "value": "true"
}
```

3. Config Update 
```
curl --location '{{baseUrl}}/v2/configs/test_v2_config_1' \
--header 'Content-Type: application/json' \
--header 'x-tenant-id: public' \
--header 'authorization: admin-api-key=test_admin' \
--data '{
    "value": "false"
}'
```
Response:
```
{
    "key": "test_v2_config_1",
    "value": "true"
}
```


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
