Ship growth intelligence and demo polish
CI / verify (push) Successful in 3m51s

This commit is contained in:
2026-08-13 04:44:14 -07:00
parent a6167629cc
commit 1318c0b841
14 changed files with 112 additions and 35 deletions
+19 -5
View File
@@ -50,6 +50,7 @@ export interface GrowthReport {
rulesetVersion: string;
computedAt: string;
customers: GrowthCustomer[];
customersTruncated: boolean;
idleSupply: GrowthIdleSupply[];
}
@@ -63,7 +64,7 @@ export class CustomerLifecycleService {
this.capacity = new CapacityService(db);
}
async report(): Promise<GrowthReport> {
async report(accountId?: string): Promise<GrowthReport> {
const now = this.clock();
const accountRows = await this.db
.select({
@@ -75,13 +76,25 @@ export class CustomerLifecycleService {
lastActivityAt: accounts.lastActivityAt,
})
.from(accounts)
.where(and(or(eq(accounts.side, 'demand'), eq(accounts.side, 'both')), isNull(accounts.archivedAt)))
.where(and(
or(eq(accounts.side, 'demand'), eq(accounts.side, 'both')),
isNull(accounts.archivedAt),
accountId ? eq(accounts.id, accountId) : undefined,
))
.orderBy(desc(accounts.updatedAt))
.limit(200);
.limit(accountId ? 1 : 201);
const customersTruncated = accountRows.length > 200;
if (customersTruncated) accountRows.length = 200;
const accountIds = accountRows.map((account) => account.id);
if (!accountIds.length) {
const idleSupply = await this.readIdleSupply();
return { rulesetVersion: 'growth-r1-2026-08-13', computedAt: now.toISOString(), customers: [], idleSupply };
return {
rulesetVersion: 'growth-r1-2026-08-13',
computedAt: now.toISOString(),
customers: [],
customersTruncated: false,
idleSupply,
};
}
const [dealRows, contractRows, activityRows] = await Promise.all([
@@ -164,12 +177,13 @@ export class CustomerLifecycleService {
rulesetVersion: customers[0]?.lifecycle.rulesetVersion ?? 'growth-r1-2026-08-13',
computedAt: now.toISOString(),
customers,
customersTruncated,
idleSupply,
};
}
async account(accountId: string): Promise<GrowthCustomer | null> {
const report = await this.report();
const report = await this.report(accountId);
return report.customers.find((customer) => customer.account.id === accountId) ?? null;
}