Bug: feat(analytics): refactor and rewrite authentication related analytics



Need to refactor and re-write the authentication related analytics.
The table which should be queried is `authentications`.

The existing metrics need to be modified and a few new metrics should be created to provide enhanced insights into authentication related data.
diff --git a/crates/analytics/src/auth_events/accumulator.rs b/crates/analytics/src/auth_events/accumulator.rs
index 2958030c8da..446ac6ac8c2 100644
--- a/crates/analytics/src/auth_events/accumulator.rs
+++ b/crates/analytics/src/auth_events/accumulator.rs
@@ -4,7 +4,7 @@ use super::metrics::AuthEventMetricRow;
 
 #[derive(Debug, Default)]
 pub struct AuthEventMetricsAccumulator {
-    pub three_ds_sdk_count: CountAccumulator,
+    pub authentication_count: CountAccumulator,
     pub authentication_attempt_count: CountAccumulator,
     pub authentication_success_count: CountAccumulator,
     pub challenge_flow_count: CountAccumulator,
@@ -47,7 +47,7 @@ impl AuthEventMetricAccumulator for CountAccumulator {
 impl AuthEventMetricsAccumulator {
     pub fn collect(self) -> AuthEventMetricsBucketValue {
         AuthEventMetricsBucketValue {
-            three_ds_sdk_count: self.three_ds_sdk_count.collect(),
+            authentication_count: self.authentication_count.collect(),
             authentication_attempt_count: self.authentication_attempt_count.collect(),
             authentication_success_count: self.authentication_success_count.collect(),
             challenge_flow_count: self.challenge_flow_count.collect(),
diff --git a/crates/analytics/src/auth_events/core.rs b/crates/analytics/src/auth_events/core.rs
index 3fd134bc498..75bdf4de149 100644
--- a/crates/analytics/src/auth_events/core.rs
+++ b/crates/analytics/src/auth_events/core.rs
@@ -18,7 +18,6 @@ use crate::{
 pub async fn get_metrics(
     pool: &AnalyticsProvider,
     merchant_id: &common_utils::id_type::MerchantId,
-    publishable_key: &String,
     req: GetAuthEventMetricRequest,
 ) -> AnalyticsResult<MetricsResponse<MetricsBucketResponse>> {
     let mut metrics_accumulator: HashMap<
@@ -30,14 +29,12 @@ pub async fn get_metrics(
     for metric_type in req.metrics.iter().cloned() {
         let req = req.clone();
         let merchant_id_scoped = merchant_id.to_owned();
-        let publishable_key_scoped = publishable_key.to_owned();
         let pool = pool.clone();
         set.spawn(async move {
             let data = pool
                 .get_auth_event_metrics(
                     &metric_type,
                     &merchant_id_scoped,
-                    &publishable_key_scoped,
                     req.time_series.map(|t| t.granularity),
                     &req.time_range,
                 )
@@ -56,8 +53,8 @@ pub async fn get_metrics(
         for (id, value) in data? {
             let metrics_builder = metrics_accumulator.entry(id).or_default();
             match metric {
-                AuthEventMetrics::ThreeDsSdkCount => metrics_builder
-                    .three_ds_sdk_count
+                AuthEventMetrics::AuthenticationCount => metrics_builder
+                    .authentication_count
                     .add_metrics_bucket(&value),
                 AuthEventMetrics::AuthenticationAttemptCount => metrics_builder
                     .authentication_attempt_count
diff --git a/crates/analytics/src/auth_events/metrics.rs b/crates/analytics/src/auth_events/metrics.rs
index 4a1fbd0e147..f3f0354818c 100644
--- a/crates/analytics/src/auth_events/metrics.rs
+++ b/crates/analytics/src/auth_events/metrics.rs
@@ -12,22 +12,22 @@ use crate::{
 };
 
 mod authentication_attempt_count;
+mod authentication_count;
 mod authentication_success_count;
 mod challenge_attempt_count;
 mod challenge_flow_count;
 mod challenge_success_count;
 mod frictionless_flow_count;
 mod frictionless_success_count;
-mod three_ds_sdk_count;
 
 use authentication_attempt_count::AuthenticationAttemptCount;
+use authentication_count::AuthenticationCount;
 use authentication_success_count::AuthenticationSuccessCount;
 use challenge_attempt_count::ChallengeAttemptCount;
 use challenge_flow_count::ChallengeFlowCount;
 use challenge_success_count::ChallengeSuccessCount;
 use frictionless_flow_count::FrictionlessFlowCount;
 use frictionless_success_count::FrictionlessSuccessCount;
-use three_ds_sdk_count::ThreeDsSdkCount;
 
 #[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct AuthEventMetricRow {
@@ -45,7 +45,6 @@ where
     async fn load_metrics(
         &self,
         merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
@@ -65,50 +64,49 @@ where
     async fn load_metrics(
         &self,
         merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         match self {
-            Self::ThreeDsSdkCount => {
-                ThreeDsSdkCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+            Self::AuthenticationCount => {
+                AuthenticationCount
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::AuthenticationAttemptCount => {
                 AuthenticationAttemptCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::AuthenticationSuccessCount => {
                 AuthenticationSuccessCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::ChallengeFlowCount => {
                 ChallengeFlowCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::ChallengeAttemptCount => {
                 ChallengeAttemptCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::ChallengeSuccessCount => {
                 ChallengeSuccessCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::FrictionlessFlowCount => {
                 FrictionlessFlowCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::FrictionlessSuccessCount => {
                 FrictionlessSuccessCount
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
         }
diff --git a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
index 5faeefec686..2d34344905e 100644
--- a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
+++ b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
@@ -1,9 +1,9 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
-    TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
+use common_enums::AuthenticationStatus;
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
 use time::PrimitiveDateTime;
@@ -29,14 +29,13 @@ where
 {
     async fn load_metrics(
         &self,
-        _merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
+        merchant_id: &common_utils::id_type::MerchantId,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,30 +44,26 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
-
-        query_builder
-            .add_filter_clause("merchant_id", publishable_key)
-            .switch()?;
-
         query_builder
-            .add_bool_filter_clause("first_event", 1)
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("event_name", SdkEventNames::AuthenticationCallInit)
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("log_type", "INFO")
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("category", "API")
+            .add_negative_filter_clause("authentication_status", AuthenticationStatus::Pending)
             .switch()?;
 
         time_range
@@ -76,9 +71,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs b/crates/analytics/src/auth_events/metrics/authentication_count.rs
similarity index 69%
rename from crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs
rename to crates/analytics/src/auth_events/metrics/authentication_count.rs
index 4ce10c9aad3..9f2311f5638 100644
--- a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs
+++ b/crates/analytics/src/auth_events/metrics/authentication_count.rs
@@ -1,8 +1,7 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
-    TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
@@ -15,10 +14,10 @@ use crate::{
 };
 
 #[derive(Default)]
-pub(super) struct ThreeDsSdkCount;
+pub(super) struct AuthenticationCount;
 
 #[async_trait::async_trait]
-impl<T> super::AuthEventMetric<T> for ThreeDsSdkCount
+impl<T> super::AuthEventMetric<T> for AuthenticationCount
 where
     T: AnalyticsDataSource + super::AuthEventMetricAnalytics,
     PrimitiveDateTime: ToSql<T>,
@@ -29,14 +28,13 @@ where
 {
     async fn load_metrics(
         &self,
-        _merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
+        merchant_id: &common_utils::id_type::MerchantId,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,30 +43,22 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
-
-        query_builder
-            .add_filter_clause("merchant_id", publishable_key)
-            .switch()?;
-
         query_builder
-            .add_bool_filter_clause("first_event", 1)
-            .switch()?;
-
-        query_builder
-            .add_filter_clause("category", "USER_EVENT")
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("log_type", "INFO")
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("event_name", SdkEventNames::ThreeDsMethod)
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         time_range
@@ -76,9 +66,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
index 663473c2d89..e887807f41c 100644
--- a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
@@ -1,9 +1,9 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
-    TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
+use common_enums::AuthenticationStatus;
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
 use time::PrimitiveDateTime;
@@ -29,14 +29,13 @@ where
 {
     async fn load_metrics(
         &self,
-        _merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
+        merchant_id: &common_utils::id_type::MerchantId,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,30 +44,26 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
-
-        query_builder
-            .add_filter_clause("merchant_id", publishable_key)
-            .switch()?;
-
         query_builder
-            .add_bool_filter_clause("first_event", 1)
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("event_name", SdkEventNames::AuthenticationCall)
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("log_type", "INFO")
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("category", "API")
+            .add_filter_clause("authentication_status", AuthenticationStatus::Success)
             .switch()?;
 
         time_range
@@ -76,9 +71,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
index 15cd86e5cc8..f1f6a397994 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
@@ -1,8 +1,7 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
-    Granularity, TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
@@ -10,7 +9,7 @@ use time::PrimitiveDateTime;
 
 use super::AuthEventMetricRow;
 use crate::{
-    query::{Aggregate, FilterTypes, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
+    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, ToSql, Window},
     types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
 };
 
@@ -30,13 +29,12 @@ where
     async fn load_metrics(
         &self,
         merchant_id: &common_utils::id_type::MerchantId,
-        _publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,22 +43,30 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
+        query_builder
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
+            .switch()?;
+
+        query_builder
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
+            .switch()?;
 
         query_builder
             .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("api_flow", AuthEventFlows::IncomingWebhookReceive)
+            .add_filter_clause("trans_status", "C".to_string())
             .switch()?;
 
         query_builder
-            .add_custom_filter_clause("request", "threeDSServerTransID", FilterTypes::Like)
+            .add_negative_filter_clause("authentication_status", "pending")
             .switch()?;
 
         time_range
@@ -68,9 +74,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
index 61b10e6fb9e..c08618cc0d0 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
@@ -1,8 +1,7 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
-    TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
@@ -29,14 +28,13 @@ where
 {
     async fn load_metrics(
         &self,
-        _merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
+        merchant_id: &common_utils::id_type::MerchantId,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,42 +43,36 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
-
         query_builder
-            .add_filter_clause("merchant_id", publishable_key)
-            .switch()?;
-
-        query_builder
-            .add_bool_filter_clause("first_event", 1)
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("category", "USER_EVENT")
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("log_type", "INFO")
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("event_name", SdkEventNames::DisplayThreeDsSdk)
+            .add_filter_clause("trans_status", "C".to_string())
             .switch()?;
 
-        query_builder.add_filter_clause("value", "C").switch()?;
-
         time_range
             .set_filter_clause(&mut query_builder)
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
index c5bf7bf81ce..3fb75efd562 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
@@ -1,9 +1,9 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
-    Granularity, TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
+use common_enums::AuthenticationStatus;
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
 use time::PrimitiveDateTime;
@@ -30,13 +30,12 @@ where
     async fn load_metrics(
         &self,
         merchant_id: &common_utils::id_type::MerchantId,
-        _publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,22 +44,30 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
+        query_builder
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
+            .switch()?;
+
+        query_builder
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
+            .switch()?;
 
         query_builder
             .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("api_flow", AuthEventFlows::IncomingWebhookReceive)
+            .add_filter_clause("authentication_status", AuthenticationStatus::Success)
             .switch()?;
 
         query_builder
-            .add_filter_clause("visitParamExtractRaw(request, 'transStatus')", "\"Y\"")
+            .add_filter_clause("trans_status", "C".to_string())
             .switch()?;
 
         time_range
@@ -68,9 +75,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
index c08cc511e16..8859c60fc37 100644
--- a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
+++ b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
@@ -1,8 +1,7 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
-    TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
@@ -29,14 +28,13 @@ where
 {
     async fn load_metrics(
         &self,
-        _merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
+        merchant_id: &common_utils::id_type::MerchantId,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,34 +43,26 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
-
-        query_builder
-            .add_filter_clause("merchant_id", publishable_key)
-            .switch()?;
-
         query_builder
-            .add_bool_filter_clause("first_event", 1)
-            .switch()?;
-
-        query_builder
-            .add_filter_clause("category", "USER_EVENT")
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("log_type", "INFO")
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("event_name", SdkEventNames::DisplayThreeDsSdk)
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_negative_filter_clause("value", "C")
+            .add_filter_clause("trans_status", "Y".to_string())
             .switch()?;
 
         time_range
@@ -80,9 +70,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
index b310567c9db..3d5d894e7dd 100644
--- a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
@@ -1,9 +1,9 @@
 use std::collections::HashSet;
 
 use api_models::analytics::{
-    auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
-    Granularity, TimeRange,
+    auth_events::AuthEventMetricsBucketIdentifier, Granularity, TimeRange,
 };
+use common_enums::AuthenticationStatus;
 use common_utils::errors::ReportSwitchExt;
 use error_stack::ResultExt;
 use time::PrimitiveDateTime;
@@ -30,13 +30,12 @@ where
     async fn load_metrics(
         &self,
         merchant_id: &common_utils::id_type::MerchantId,
-        _publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
-            QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
+            QueryBuilder::new(AnalyticsCollection::Authentications);
 
         query_builder
             .add_select_column(Aggregate::Count {
@@ -45,22 +44,30 @@ where
             })
             .switch()?;
 
-        if let Some(granularity) = granularity {
-            query_builder
-                .add_granularity_in_mins(granularity)
-                .switch()?;
-        }
+        query_builder
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
+            .switch()?;
 
         query_builder
-            .add_filter_clause("merchant_id", merchant_id.get_string_repr())
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
             .switch()?;
 
         query_builder
-            .add_filter_clause("api_flow", AuthEventFlows::PaymentsExternalAuthentication)
+            .add_filter_clause("merchant_id", merchant_id)
             .switch()?;
 
         query_builder
-            .add_filter_clause("visitParamExtractRaw(response, 'transStatus')", "\"Y\"")
+            .add_filter_clause("trans_status", "Y".to_string())
+            .switch()?;
+
+        query_builder
+            .add_filter_clause("authentication_status", AuthenticationStatus::Success)
             .switch()?;
 
         time_range
@@ -68,9 +75,9 @@ where
             .attach_printable("Error filtering time range")
             .switch()?;
 
-        if let Some(_granularity) = granularity.as_ref() {
-            query_builder
-                .add_group_by_clause("time_bucket")
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
                 .attach_printable("Error adding granularity")
                 .switch()?;
         }
diff --git a/crates/analytics/src/clickhouse.rs b/crates/analytics/src/clickhouse.rs
index cd870c12b23..1c86e7cbcf6 100644
--- a/crates/analytics/src/clickhouse.rs
+++ b/crates/analytics/src/clickhouse.rs
@@ -138,6 +138,7 @@ impl AnalyticsDataSource for ClickhouseClient {
             | AnalyticsCollection::FraudCheck
             | AnalyticsCollection::PaymentIntent
             | AnalyticsCollection::PaymentIntentSessionized
+            | AnalyticsCollection::Authentications
             | AnalyticsCollection::Dispute => {
                 TableEngine::CollapsingMergeTree { sign: "sign_flag" }
             }
@@ -457,6 +458,7 @@ impl ToSql<ClickhouseClient> for AnalyticsCollection {
             Self::Dispute => Ok("dispute".to_string()),
             Self::DisputeSessionized => Ok("sessionizer_dispute".to_string()),
             Self::ActivePaymentsAnalytics => Ok("active_payments".to_string()),
+            Self::Authentications => Ok("authentications".to_string()),
         }
     }
 }
diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs
index 0ad8886b820..ef7108e8ef7 100644
--- a/crates/analytics/src/lib.rs
+++ b/crates/analytics/src/lib.rs
@@ -909,7 +909,6 @@ impl AnalyticsProvider {
         &self,
         metric: &AuthEventMetrics,
         merchant_id: &common_utils::id_type::MerchantId,
-        publishable_key: &str,
         granularity: Option<Granularity>,
         time_range: &TimeRange,
     ) -> types::MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
@@ -917,14 +916,13 @@ impl AnalyticsProvider {
             Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)),
             Self::Clickhouse(pool) => {
                 metric
-                    .load_metrics(merchant_id, publishable_key, granularity, time_range, pool)
+                    .load_metrics(merchant_id, granularity, time_range, pool)
                     .await
             }
             Self::CombinedCkh(_sqlx_pool, ckh_pool) | Self::CombinedSqlx(_sqlx_pool, ckh_pool) => {
                 metric
                     .load_metrics(
                         merchant_id,
-                        publishable_key,
                         granularity,
                         // Since API events are ckh only use ckh here
                         time_range,
diff --git a/crates/analytics/src/query.rs b/crates/analytics/src/query.rs
index f449ba2f9b5..59cb8743448 100644
--- a/crates/analytics/src/query.rs
+++ b/crates/analytics/src/query.rs
@@ -19,6 +19,7 @@ use api_models::{
     },
     refunds::RefundStatus,
 };
+use common_enums::{AuthenticationStatus, TransactionStatus};
 use common_utils::{
     errors::{CustomResult, ParsingError},
     id_type::{MerchantId, OrganizationId, ProfileId},
@@ -502,6 +503,8 @@ impl_to_sql_for_to_string!(
     Currency,
     RefundType,
     FrmTransactionType,
+    TransactionStatus,
+    AuthenticationStatus,
     Flow,
     &String,
     &bool,
diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs
index 653d019adeb..f3143840f34 100644
--- a/crates/analytics/src/sqlx.rs
+++ b/crates/analytics/src/sqlx.rs
@@ -1034,6 +1034,8 @@ impl ToSql<SqlxClient> for AnalyticsCollection {
             Self::Dispute => Ok("dispute".to_string()),
             Self::DisputeSessionized => Err(error_stack::report!(ParsingError::UnknownError)
                 .attach_printable("DisputeSessionized table is not implemented for Sqlx"))?,
+            Self::Authentications => Err(error_stack::report!(ParsingError::UnknownError)
+                .attach_printable("Authentications table is not implemented for Sqlx"))?,
         }
     }
 }
diff --git a/crates/analytics/src/types.rs b/crates/analytics/src/types.rs
index 86056338106..7bf8fc7d3c3 100644
--- a/crates/analytics/src/types.rs
+++ b/crates/analytics/src/types.rs
@@ -37,6 +37,7 @@ pub enum AnalyticsCollection {
     PaymentIntentSessionized,
     ConnectorEvents,
     OutgoingWebhookEvent,
+    Authentications,
     Dispute,
     DisputeSessionized,
     ApiEventsAnalytics,
diff --git a/crates/api_models/src/analytics/auth_events.rs b/crates/api_models/src/analytics/auth_events.rs
index 7791a2f3cd5..6f527551348 100644
--- a/crates/api_models/src/analytics/auth_events.rs
+++ b/crates/api_models/src/analytics/auth_events.rs
@@ -5,6 +5,29 @@ use std::{
 
 use super::NameDescription;
 
+#[derive(
+    Debug,
+    serde::Serialize,
+    serde::Deserialize,
+    strum::AsRefStr,
+    PartialEq,
+    PartialOrd,
+    Eq,
+    Ord,
+    strum::Display,
+    strum::EnumIter,
+    Clone,
+    Copy,
+)]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum AuthEventDimensions {
+    #[serde(rename = "authentication_status")]
+    AuthenticationStatus,
+    #[serde(rename = "trans_status")]
+    TransactionStatus,
+}
+
 #[derive(
     Clone,
     Debug,
@@ -20,7 +43,7 @@ use super::NameDescription;
 #[strum(serialize_all = "snake_case")]
 #[serde(rename_all = "snake_case")]
 pub enum AuthEventMetrics {
-    ThreeDsSdkCount,
+    AuthenticationCount,
     AuthenticationAttemptCount,
     AuthenticationSuccessCount,
     ChallengeFlowCount,
@@ -48,7 +71,7 @@ pub enum AuthEventFlows {
 }
 
 pub mod metric_behaviour {
-    pub struct ThreeDsSdkCount;
+    pub struct AuthenticationCount;
     pub struct AuthenticationAttemptCount;
     pub struct AuthenticationSuccessCount;
     pub struct ChallengeFlowCount;
@@ -96,7 +119,7 @@ impl PartialEq for AuthEventMetricsBucketIdentifier {
 
 #[derive(Debug, serde::Serialize)]
 pub struct AuthEventMetricsBucketValue {
-    pub three_ds_sdk_count: Option<u64>,
+    pub authentication_count: Option<u64>,
     pub authentication_attempt_count: Option<u64>,
     pub authentication_success_count: Option<u64>,
     pub challenge_flow_count: Option<u64>,
diff --git a/crates/router/src/analytics.rs b/crates/router/src/analytics.rs
index 8fb4f2ac2c1..deaf84bb009 100644
--- a/crates/router/src/analytics.rs
+++ b/crates/router/src/analytics.rs
@@ -975,7 +975,6 @@ pub mod routes {
                 analytics::auth_events::get_metrics(
                     &state.pool,
                     auth.merchant_account.get_id(),
-                    &auth.merchant_account.publishable_key,
                     req,
                 )
                 .await

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

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

## Description
<!-- Describe your changes in detail -->
Refactored and re-wrote the authentication related analytics.
The table being queried is now `authentications`.

The following metrics were modified:
- Authentication Attempt Count
- Authentication Count
- Authentication Success Count
- Challenge Attempt Count
- Challenge Flow Count
- Challenge Success Count
- Frictionless Flow Count
- Frictionless Success Count

### 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).
-->
Get better insights into authentications related data through analytics

## 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)?
-->
Hit the following curls:

#### Authentication Attempt Count:

```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "authentication_attempt_count" 
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": 80,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Authentication Count:

```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "authentication_count"  
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": 95,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Authentication Success Count:

```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "authentication_success_count"   
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": 75,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Challenge Flow Count:
```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "challenge_flow_count"
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": 1,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Challenge Attempt Count:
```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "challenge_attempt_count" 
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": 1,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Challenge Sccess Count:
```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "challenge_success_count"   
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": 1,
            "frictionless_flow_count": null,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Frictionless Flow Count:
```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "frictionless_flow_count"
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": 74,
            "frictionless_success_count": null,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```

#### Frictionless Success Count:
```bash
curl --location 'http://localhost:8080/analytics/v1/metrics/auth_events' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiYWFiNWIxNDEtNjQwOC00YTUyLTk2MjMtNTVhNTgxMTU1M2U4IiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzQwNDE0OTA5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc0MTI3NDY4NSwib3JnX2lkIjoib3JnX1QwSEtYNHYyRGFRT2lHUDVwRk52IiwicHJvZmlsZV9pZCI6InByb19xOWc2ZW1xcGM3YjQxTG83VVhweCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.LIExs1jjG6N5AFu5_S3oiuy77fWF0IbJmNGbK8HHLXI' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-02-01T18:30:00Z",
            "endTime": "2025-02-28T09:22:00Z"
        },
        "source": "BATCH",
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "metrics": [
            "frictionless_success_count"
        ],
        "delta": true
    }
]'
```

Sample Output:
```json
{
    "queryData": [
        {
            "authentication_count": null,
            "authentication_attempt_count": null,
            "authentication_success_count": null,
            "challenge_flow_count": null,
            "challenge_attempt_count": null,
            "challenge_success_count": null,
            "frictionless_flow_count": null,
            "frictionless_success_count": 74,
            "time_bucket": null
        }
    ],
    "metaData": [
        {
            "current_time_range": {
                "start_time": "2025-02-01T18:30:00.000Z",
                "end_time": "2025-02-28T09:22:00.000Z"
            }
        }
    ]
}
```
Queries:

#### Authentication Attempt Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND authentication_status != 'pending' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```
#### Authentication Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Authentication Success Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND authentication_status = 'success' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Challenge Attempt Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND trans_status = 'C' AND authentication_status != 'pending' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Challenge Flow Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND trans_status = 'C' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Challenge Success Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND authentication_status = 'success' AND trans_status = 'C' AND created_at >= '1726079400' AND created_at <= '1727256120' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Frictionless Flow Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND trans_status = 'Y' AND created_at >= '1738402351' AND created_at <= '1740216751' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```

#### Frictionless Success Count:

```bash
SELECT sum(sign_flag) as count, min(created_at) as start_bucket, max(created_at) as end_bucket FROM authentications WHERE ( merchant_id = 'merchant_1740414909' AND trans_status = 'Y' AND authentication_status = 'success' AND created_at >= '1738402351' AND created_at <= '1740216751' ) GROUP BY toStartOfDay(created_at) HAVING sum(sign_flag) >= '1'
```




## 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
