From 0bfd4bdf226b22232ba2a26da50499c3e256f3c9 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Tue, 17 Feb 2026 11:13:55 -0800 Subject: [PATCH] feat(telemetry): geo distribution endpoint (GET /telemetry/geo) with Cosmos GROUP BY aggregation --- .../src/modules/telemetry/repository.ts | 29 +++++++++++++++++++ .../src/modules/telemetry/routes.ts | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/services/platform-service/src/modules/telemetry/repository.ts b/services/platform-service/src/modules/telemetry/repository.ts index 6cb4f66c..410c243d 100644 --- a/services/platform-service/src/modules/telemetry/repository.ts +++ b/services/platform-service/src/modules/telemetry/repository.ts @@ -113,6 +113,35 @@ export async function queryEvents( }; } +export async function queryGeoDistribution( + productId: string, + from?: string, + to?: string +): Promise> { + const conditions: string[] = [ + 'c.productId = @productId', + 'IS_DEFINED(c.countryCode)', + 'c.countryCode != null', + ]; + const parameters: Array<{ name: string; value: string }> = [ + { name: '@productId', value: productId }, + ]; + if (from) { + conditions.push('c.occurredAt >= @from'); + parameters.push({ name: '@from', value: from }); + } + if (to) { + conditions.push('c.occurredAt <= @to'); + parameters.push({ name: '@to', value: to }); + } + + const query = `SELECT c.countryCode, COUNT(1) AS count FROM c WHERE ${conditions.join(' AND ')} GROUP BY c.countryCode`; + const { resources } = await eventsContainer() + .items.query<{ countryCode: string; count: number }>({ query, parameters }) + .fetchAll(); + return resources.sort((a, b) => b.count - a.count); +} + export async function deleteEventsByUserId(productId: string, userId: string): Promise { // Find all events for this user, then delete them const { resources } = await eventsContainer() diff --git a/services/platform-service/src/modules/telemetry/routes.ts b/services/platform-service/src/modules/telemetry/routes.ts index 4bfe9e1e..bce67fb3 100644 --- a/services/platform-service/src/modules/telemetry/routes.ts +++ b/services/platform-service/src/modules/telemetry/routes.ts @@ -880,6 +880,15 @@ export async function telemetryRoutes(app: FastifyInstance) { return updated; }); + // ── Admin: geo distribution ───────────────────────────── + app.get('/telemetry/geo', async req => { + requireAdmin(req); + const productId = getRequestProductId(req); + const { from, to } = req.query as { from?: string; to?: string }; + const distribution = await repo.queryGeoDistribution(productId, from, to); + return { distribution }; + }); + // ── Admin: ingestion metrics (JSON) ───────────────────── app.get('/telemetry/metrics', async req => { requireAdmin(req);