Files
CapaKraken/packages/api/src/router/scenario.ts
T

55 lines
1.9 KiB
TypeScript

import { PermissionKey } from "@capakraken/shared";
import { z } from "zod";
import { createTRPCRouter, controllerProcedure, planningReadProcedure, requirePermission } from "../trpc.js";
import { applyProjectScenario } from "./scenario-apply.js";
import { readProjectScenarioBaseline } from "./scenario-baseline.js";
import { simulateProjectScenario } from "./scenario-simulation.js";
const ScenarioChangeSchema = z.object({
/** Existing assignment to modify — omit to add a new allocation */
assignmentId: z.string().optional(),
resourceId: z.string().optional(),
roleId: z.string().optional(),
startDate: z.coerce.date(),
endDate: z.coerce.date(),
hoursPerDay: z.number().min(0).max(24),
/** Set to true to mark an existing assignment for removal */
remove: z.boolean().optional(),
});
const SimulateInputSchema = z.object({
projectId: z.string(),
changes: z.array(ScenarioChangeSchema).min(1),
});
export const scenarioRouter = createTRPCRouter({
/**
* Returns current allocations/costs for a project — the baseline for comparison.
*/
getProjectBaseline: planningReadProcedure
.input(z.object({ projectId: z.string() }))
.query(async ({ ctx, input }) => {
requirePermission(ctx, PermissionKey.VIEW_COSTS);
return readProjectScenarioBaseline(ctx.db, input.projectId);
}),
/**
* Pure simulation: computes cost/hours/utilization impact of scenario changes
* without persisting anything.
*/
simulate: controllerProcedure
.input(SimulateInputSchema)
.mutation(async ({ ctx, input }) => simulateProjectScenario(ctx.db, input)),
/**
* Applies a scenario: creates real assignments from scenario changes.
* Manager+ access required.
*/
applyScenario: controllerProcedure
.input(SimulateInputSchema)
.mutation(async ({ ctx, input }) => applyProjectScenario(ctx.db, {
...input,
userId: ctx.dbUser?.id,
})),
});