@@ -5,20 +5,20 @@ const { Developer, Project, Log, ApiAnalytics, PlatformEvent, DeveloperActivity
55 * Checked upstream via the isAdmin flag on the JWT payload,
66 * but we double-check here for defence in depth.
77 */
8- function requireAdmin ( req , res ) {
8+ function requireAdmin ( req , res , next ) {
99 if ( ! req . user ?. isAdmin ) {
10- res . status ( 403 ) . json ( { success : false , data : { } , message : 'Admin access required.' } ) ;
11- return false ;
10+ return res . status ( 403 ) . json ( { success : false , data : { } , message : 'Admin access required.' } ) ;
1211 }
13- return true ;
12+ return next ( ) ;
1413}
1514
15+ module . exports . requireAdmin = requireAdmin ;
16+
1617// ---------------------------------------------------------------------------
1718// GET /api/admin/metrics/overview
1819// Platform-wide snapshot: signups, verified devs, active projects, total calls.
1920// ---------------------------------------------------------------------------
2021module . exports . getOverview = async ( req , res ) => {
21- if ( ! requireAdmin ( req , res ) ) return ;
2222 try {
2323 const sevenDaysAgo = new Date ( ) ;
2424 sevenDaysAgo . setUTCDate ( sevenDaysAgo . getUTCDate ( ) - 7 ) ;
@@ -62,7 +62,6 @@ module.exports.getOverview = async (req, res) => {
6262// Platform-wide funnel: count of devs who completed each activation step.
6363// ---------------------------------------------------------------------------
6464module . exports . getActivationFunnel = async ( req , res ) => {
65- if ( ! requireAdmin ( req , res ) ) return ;
6665 try {
6766 const FUNNEL_STEPS = [
6867 'signup_completed' ,
@@ -117,7 +116,6 @@ module.exports.getActivationFunnel = async (req, res) => {
117116// D1/D7/D30 retention for developers who signed up in a given month.
118117// ---------------------------------------------------------------------------
119118module . exports . getCohorts = async ( req , res ) => {
120- if ( ! requireAdmin ( req , res ) ) return ;
121119 try {
122120 const { month } = req . query ; // e.g. "2026-05"
123121 if ( ! month || ! / ^ \d { 4 } - \d { 2 } $ / . test ( month ) ) {
@@ -237,32 +235,40 @@ module.exports.getCohorts = async (req, res) => {
237235// Platform-wide feature breakdown from DeveloperActivity (last 30 days).
238236// ---------------------------------------------------------------------------
239237module . exports . getFeatureUsage = async ( req , res ) => {
240- if ( ! requireAdmin ( req , res ) ) return ;
241238 try {
242239 const thirtyDaysAgo = new Date ( ) ;
243240 thirtyDaysAgo . setUTCDate ( thirtyDaysAgo . getUTCDate ( ) - 30 ) ;
244241
245242 const agg = await DeveloperActivity . aggregate ( [
246243 { $match : { date : { $gte : thirtyDaysAgo } } } ,
247244 {
248- $group : {
249- _id : null ,
250- totalApiCalls : { $sum : '$apiCallCount' } ,
251- totalMailSent : { $sum : '$mailSentCount' } ,
252- totalStorageUploads : { $sum : '$storageUploadsCount' } ,
253- totalWebhooksFired : { $sum : '$webhookTriggeredCount' } ,
254- activeDevelopers : { $addToSet : '$developerId' } ,
245+ $facet : {
246+ totals : [
247+ {
248+ $group : {
249+ _id : null ,
250+ totalApiCalls : { $sum : '$apiCallCount' } ,
251+ totalMailSent : { $sum : '$mailSentCount' } ,
252+ totalStorageUploads : { $sum : '$storageUploadsCount' } ,
253+ totalWebhooksFired : { $sum : '$webhookTriggeredCount' } ,
254+ } ,
255+ } ,
256+ ] ,
257+ activeDevelopers : [
258+ { $group : { _id : '$developerId' } } ,
259+ { $count : 'count' } ,
260+ ] ,
255261 } ,
256262 } ,
257263 ] ) ;
258264
259- const result = agg [ 0 ] || {
265+ const result = agg [ 0 ] ?. totals ?. [ 0 ] || {
260266 totalApiCalls : 0 ,
261267 totalMailSent : 0 ,
262268 totalStorageUploads : 0 ,
263269 totalWebhooksFired : 0 ,
264- activeDevelopers : [ ] ,
265270 } ;
271+ const activeDeveloperCount = agg [ 0 ] ?. activeDevelopers ?. [ 0 ] ?. count || 0 ;
266272
267273 return res . json ( {
268274 success : true ,
@@ -272,7 +278,7 @@ module.exports.getFeatureUsage = async (req, res) => {
272278 totalMailSent : result . totalMailSent ,
273279 totalStorageUploads : result . totalStorageUploads ,
274280 totalWebhooksFired : result . totalWebhooksFired ,
275- activeDevelopers : result . activeDevelopers . length ,
281+ activeDevelopers : activeDeveloperCount ,
276282 } ,
277283 message : '' ,
278284 } ) ;
@@ -287,7 +293,6 @@ module.exports.getFeatureUsage = async (req, res) => {
287293// Global error rate and latency across all projects (last 24h from ApiAnalytics).
288294// ---------------------------------------------------------------------------
289295module . exports . getReliability = async ( req , res ) => {
290- if ( ! requireAdmin ( req , res ) ) return ;
291296 try {
292297 const { ApiAnalytics } = require ( '@urbackend/common' ) ;
293298 const since = new Date ( Date . now ( ) - 24 * 60 * 60 * 1000 ) ;
@@ -332,7 +337,6 @@ module.exports.getReliability = async (req, res) => {
332337// Most active projects by API calls in the last 7 days.
333338// ---------------------------------------------------------------------------
334339module . exports . getTopProjects = async ( req , res ) => {
335- if ( ! requireAdmin ( req , res ) ) return ;
336340 try {
337341 const sevenDaysAgo = new Date ( ) ;
338342 sevenDaysAgo . setUTCDate ( sevenDaysAgo . getUTCDate ( ) - 7 ) ;
@@ -372,7 +376,6 @@ module.exports.getTopProjects = async (req, res) => {
372376// Projects with zero API calls in the last 14 days that had prior activity.
373377// ---------------------------------------------------------------------------
374378module . exports . getChurnSignals = async ( req , res ) => {
375- if ( ! requireAdmin ( req , res ) ) return ;
376379 try {
377380 const fourteenDaysAgo = new Date ( ) ;
378381 fourteenDaysAgo . setUTCDate ( fourteenDaysAgo . getUTCDate ( ) - 14 ) ;
0 commit comments