feat(agent-api): GET /api/agent/projects

Implements the route to fetch all projects across all clients the owner has.
No status filtering—agents drafting a plan need to see paused/completed projects.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-09-25 22:31:31 +02:00
parent ff23890809
commit 4fef9233c8

View file

@ -0,0 +1,42 @@
import { getAdminPb } from "@/lib/pb/admin";
import { requireAgentToken } from "@/lib/agent/auth";
import { jsonOk } from "@/lib/http/json";
import type { ClientRecord, ProjectRecord } from "@/lib/pb/types";
/**
* GET /api/agent/projects — every project across every client the owner has.
*
* No status filtering: an agent drafting a plan needs to see a paused or
* completed project too, not just active ones — it is planning, not
* browsing the way the home page is.
*/
export async function GET(request: Request): Promise<Response> {
const denied = requireAgentToken(request);
if (denied) return denied;
const pb = await getAdminPb();
const [projects, clients] = await Promise.all([
pb.collection("projects").getFullList<ProjectRecord>({ sort: "name" }),
pb.collection("clients").getFullList<ClientRecord>(),
]);
const clientsById = new Map(clients.map((c) => [c.id, c]));
const out = projects
.map((project) => {
const client = clientsById.get(project.client);
if (!client) return null;
return {
id: project.id,
name: project.name,
slug: project.slug,
client: { id: client.id, name: client.name, slug: client.slug },
kind: project.kind,
status: project.status,
};
})
.filter((p): p is NonNullable<typeof p> => p !== null);
return jsonOk(out);
}