feat(telemetry): geo distribution endpoint (GET /telemetry/geo) with Cosmos GROUP BY aggregation

This commit is contained in:
saravanakumardb1 2026-02-17 11:13:55 -08:00
parent 70fa6f4738
commit 0bfd4bdf22
2 changed files with 38 additions and 0 deletions

View File

@ -113,6 +113,35 @@ export async function queryEvents(
};
}
export async function queryGeoDistribution(
productId: string,
from?: string,
to?: string
): Promise<Array<{ countryCode: string; count: number }>> {
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<number> {
// Find all events for this user, then delete them
const { resources } = await eventsContainer()

View File

@ -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);