feat(boss-dashboard): add /api/v1/boss-dashboard route handler
This commit is contained in:
parent
5a944bc1f9
commit
8ecacf78fe
1 changed files with 61 additions and 0 deletions
61
src/app/api/v1/boss-dashboard/route.ts
Normal file
61
src/app/api/v1/boss-dashboard/route.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { getBossDashboardData, type BossWindow } from "@/lib/server/boss-dashboard-service";
|
||||
|
||||
/**
|
||||
* GET /api/v1/boss-dashboard?window=today|week|month
|
||||
*
|
||||
* Read model for the boss's phone dashboard at `/m`. Returns a single
|
||||
* window's worth of aggregates (~3-5 KB). Auth via the PB browser
|
||||
* session — same pattern as /api/v1/dashboard.
|
||||
*/
|
||||
export const runtime = "nodejs";
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const VALID_WINDOWS: BossWindow[] = ["today", "week", "month"];
|
||||
|
||||
async function assertBrowserSession(req: NextRequest) {
|
||||
const auth = req.headers.get("authorization");
|
||||
if (!auth) {
|
||||
throw Object.assign(new Error("Not authenticated."), { status: 401 });
|
||||
}
|
||||
const pbUrl =
|
||||
process.env.NEXT_PUBLIC_POCKETBASE_URL || "http://127.0.0.1:8090";
|
||||
const token = auth.startsWith("Bearer ") ? auth.slice(7) : auth;
|
||||
const res = await fetch(
|
||||
`${pbUrl.replace(/\/$/, "")}/api/collections/users/auth-refresh`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { Authorization: token },
|
||||
signal: AbortSignal.timeout(5000),
|
||||
},
|
||||
);
|
||||
if (!res.ok) {
|
||||
throw Object.assign(new Error("Invalid or expired session."), {
|
||||
status: 401,
|
||||
});
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const user = await assertBrowserSession(req);
|
||||
|
||||
const url = new URL(req.url);
|
||||
const raw = url.searchParams.get("window") ?? "today";
|
||||
if (!VALID_WINDOWS.includes(raw as BossWindow)) {
|
||||
return NextResponse.json(
|
||||
{ error: `Invalid window: ${raw}` },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const data = await getBossDashboardData({ window: raw as BossWindow });
|
||||
return NextResponse.json({ ...data, viewerName: user?.record?.name ?? null });
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Failed to load dashboard";
|
||||
const status = (error as Error & { status?: number }).status || 500;
|
||||
return NextResponse.json({ error: message }, { status });
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue