fix command-center RPCs against prod schema and setof call
Deploy to route.crispygoat.com / deploy (push) Successful in 4m17s

Migration 0040 was written against an assumed schema and referenced
columns that don't exist in the prod orders table:
  - orders.created_at  → use orders.placed_at
  - orders.subtotal    → use orders.total_cents / 100
  - stops.date regex   → column is already DATE, not TEXT, drop the
                         ~ '^\d{4}-...$' check

Migration 0041 fixes both broken functions in place via
CREATE OR REPLACE FUNCTION.

The action layer at src/actions/platform/command-center.ts used
SELECT fn() AS "fn" for all platform RPCs, but two of the three
return TABLE(...) (setof) — the correct syntax is SELECT * FROM fn().
The platformRPC<T> helper now takes a kind: 'scalar' | 'setof' flag
and emits the right SQL.

Verified on prod:
  METRICS:    { orders_today:0, active_brands:1, active_routes:538, ... }
  BRAND_HEALTH: 1 row (Tuxedo Corn), 538 active_stops, 0 failed, healthy schema
  ACTIVITY:   0 rows (operational_events has no brand_id in payload, no error)
This commit is contained in:
Tyler
2026-06-17 10:02:46 -06:00
parent 4f22da65d8
commit 3d4b98d703
2 changed files with 171 additions and 8 deletions
+24 -8
View File
@@ -64,34 +64,50 @@ export type CreatePainLogData = {
// ── Internal RPC helper ──────────────────────────────────────────────────────
async function platformRPC<T>(rpcName: string): Promise<T> {
/**
* Call a platform RPC. The action layer needs to know whether the function
* returns a scalar (JSONB) or a setof (TABLE(...)) — `SELECT fn() AS "fn"`
* only works for scalar returns; setof functions need `SELECT * FROM fn()`.
*
* - `kind: "scalar"` → wraps the single result column in a JSON value
* - `kind: "setof"` → returns the rows directly as an array
*/
async function platformRPC<T>(
rpcName: string,
kind: "scalar" | "setof" = "scalar",
): Promise<T> {
const adminUser = await getAdminUser();
if (!adminUser) throw new Error("Not authenticated");
if (adminUser.role !== "platform_admin") throw new Error("Access denied: platform admin only");
if (kind === "setof") {
const { rows } = await pool.query(
`SELECT * FROM ${rpcName}()`,
);
return rows as unknown as T;
}
// scalar: e.g. JSONB return — single cell, possibly null
const { rows } = await pool.query<Record<string, T>>(
`SELECT ${rpcName}() AS "${rpcName}"`,
);
const data = rows[0]?.[rpcName];
if (data == null) {
return null as T;
}
if (data == null) return null as T;
return data as T;
}
// ── Platform actions ─────────────────────────────────────────────────────────
export async function getPlatformMetrics(): Promise<PlatformMetrics> {
return platformRPC<PlatformMetrics>("get_platform_command_center_metrics");
return platformRPC<PlatformMetrics>("get_platform_command_center_metrics", "scalar");
}
export async function getPlatformActivityFeed(): Promise<ActivityEvent[]> {
return platformRPC<ActivityEvent[]>("get_platform_activity_feed");
return platformRPC<ActivityEvent[]>("get_platform_activity_feed", "setof");
}
export async function getBrandHealthSnapshot(): Promise<BrandHealth[]> {
return platformRPC<BrandHealth[]>("get_brand_health_snapshot");
return platformRPC<BrandHealth[]>("get_brand_health_snapshot", "setof");
}
export async function getPainLog(): Promise<PainLogItem[]> {