/** * Org-admin capacity policy routes (ADR-0022). */ import type { PrismaClient } from "@prisma/client"; import type { FastifyInstance } from "fastify"; import { getCapacityPolicy, setCapacityPolicy } from "../../org/capacityPolicy.js"; import { isCapacityDimension } from "../../capacity/dimensions.js"; import { requireOrgRole, type GuardDeps } from "../auth/guards.js"; import { handleRouteError } from "../errors.js"; export async function registerCapacityRoutes( app: FastifyInstance, config: { readonly prisma: PrismaClient; readonly sessionSecret: string }, ): Promise { const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret }; app.get("/api/org/:orgSlug/capacity-policy", async (request, reply) => { try { const { orgSlug } = request.params as { orgSlug: string }; const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug }); if (auth === null) return; return await getCapacityPolicy(config.prisma, auth.organization.id); } catch (err) { return handleRouteError(reply, err); } }); app.put("/api/org/:orgSlug/capacity-policy", async (request, reply) => { try { const { orgSlug } = request.params as { orgSlug: string }; const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug }); if (auth === null) return; const body = request.body as { limits?: unknown }; if (body?.limits === null || typeof body.limits !== "object") { return reply.status(400).send({ error: { code: "bad_request", message: "limits object is required" }, }); } const limits: Record = {}; for (const [key, value] of Object.entries(body.limits as Record)) { if (!isCapacityDimension(key)) { return reply.status(400).send({ error: { code: "bad_request", message: `unknown capacity dimension: ${key}` }, }); } if (value === null) { limits[key] = null; } else if (typeof value === "number" && Number.isFinite(value)) { limits[key] = value; } else { return reply.status(400).send({ error: { code: "bad_request", message: `limit for ${key} must be a number or null` }, }); } } return await setCapacityPolicy(config.prisma, { organizationId: auth.organization.id, limits, }); } catch (err) { return handleRouteError(reply, err); } }); }