fix(admin): count recent users from live data

This commit is contained in:
saltbo
2026-07-21 12:22:43 -04:00
parent 40c5f10d48
commit 52c69defd7
2 changed files with 36 additions and 5 deletions
@@ -310,6 +310,29 @@ describe('admin hourly stats rollup', () => {
).rejects.toThrow('stats_bucket_must_align_to_utc_hour')
})
it('counts recent registered users live even when signup rollups are unavailable', async () => {
const { app, db } = await createTestApp()
await adminHeaders(app)
const now = new Date('2026-07-20T18:30:00.000Z')
const recentCreatedAt = new Date('2026-07-15T09:00:00.000Z').getTime()
const oldCreatedAt = new Date('2026-07-13T23:59:59.999Z').getTime()
const [{ id: seededUserId }] = await db.all<{ id: string }>(sql`SELECT id FROM user LIMIT 1`)
await db.run(sql`UPDATE user SET created_at = ${oldCreatedAt}`)
await db.run(sql`UPDATE user SET created_at = ${recentCreatedAt} WHERE id = ${seededUserId}`)
await db.run(sql`
INSERT INTO user (id, name, email, email_verified, created_at, updated_at)
VALUES ('old-overview-user', 'Old User', 'old-overview@example.com', 1, ${oldCreatedAt}, ${oldCreatedAt})
`)
const overview = await createAdminStatsRepo(db).getOverviewStatistics(now, {
from: new Date('2026-06-21T00:00:00.000Z'),
to: new Date('2026-07-20T17:59:59.999Z'),
timeZone: 'UTC',
})
expect(overview.users.new7Days).toBe(1)
})
it('rolls exact storage writes and releases into the overview trend', async () => {
const { app, db } = await createTestApp()
await adminHeaders(app)
+13 -5
View File
@@ -13,7 +13,7 @@ import type {
AdminTopShare,
AdminTransferDataQuality,
} from '@shared/types'
import { and, eq, gte, inArray, lte } from 'drizzle-orm'
import { and, eq, gte, inArray, lte, sql } from 'drizzle-orm'
import { member, organization, user } from '../../db/auth-schema'
import { matters, shares, statsRollupsHourly } from '../../db/schema'
import {
@@ -55,6 +55,7 @@ async function getOverviewStatistics(
const [
inventory,
active,
recentRegisteredUsers,
newUsersByDay,
totalUsersByDay,
activeByDay,
@@ -66,6 +67,7 @@ async function getOverviewStatistics(
] = await Promise.all([
getUserInventory(reader),
getActiveUserSnapshot(reader),
getRecentRegisteredUserCount(db, now),
getSignupsByDay(reader),
getUserTotalsByDay(reader),
getRollingActiveUserTrend(reader, effective),
@@ -80,7 +82,6 @@ async function getOverviewStatistics(
const dau = active?.dau ?? null
const wau = active?.wau ?? null
const mau = active?.mau ?? null
const recentSignups = dates.slice(-7).map((date) => (newUsersByDay.has(date) ? (newUsersByDay.get(date) ?? null) : 0))
const exactUsage = storageDataQuality.usageDriftSpaces === null || storageDataQuality.usageDriftSpaces === 0
const exactLedger = storageDataQuality.ledgerDriftSpaces === null || storageDataQuality.ledgerDriftSpaces === 0
const storageChangesExactFrom = fullStorageChangeDayFrom(storageLedgerOpening)
@@ -89,9 +90,7 @@ async function getOverviewStatistics(
users: {
total: inventory?.total ?? null,
active30Days: mau,
new7Days: recentSignups.some((value) => value === null)
? null
: recentSignups.reduce<number>((total, value) => total + (value ?? 0), 0),
new7Days: recentRegisteredUsers,
activity: {
today: dau,
last7Days: dau === null || wau === null ? null : Math.max(0, wau - dau),
@@ -120,6 +119,15 @@ async function getOverviewStatistics(
}
}
async function getRecentRegisteredUserCount(db: Database, now: Date): Promise<number> {
const from = utcDateStart(addCalendarDays(dayKey(now), -6))
const [row] = await db
.select({ count: sql<number>`COUNT(*)` })
.from(user)
.where(and(gte(user.createdAt, from), lte(user.createdAt, now)))
return Number(row.count)
}
async function getTopPersonalUsage(
db: Database,
reader: AdminStatsHourlyReader,