feat(staffing): enforce planning and cost audiences
This commit is contained in:
@@ -222,6 +222,7 @@ const COST_TOOLS = new Set([
|
||||
"get_estimate_detail",
|
||||
"get_estimate_version_snapshot",
|
||||
"find_best_project_resource",
|
||||
"get_staffing_suggestions",
|
||||
]);
|
||||
|
||||
/** Tools that follow planningReadProcedure access rules in the main API. */
|
||||
@@ -229,6 +230,9 @@ const PLANNING_READ_TOOLS = new Set([
|
||||
"list_allocations",
|
||||
"list_demands",
|
||||
"check_resource_availability",
|
||||
"get_staffing_suggestions",
|
||||
"find_capacity",
|
||||
"find_best_project_resource",
|
||||
]);
|
||||
|
||||
/** Tools that follow controllerProcedure access rules in the main API. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { rankResources } from "@capakraken/staffing";
|
||||
import { listAssignmentBookings } from "@capakraken/application";
|
||||
import type { WeekdayAvailability } from "@capakraken/shared";
|
||||
import { PermissionKey, type WeekdayAvailability } from "@capakraken/shared";
|
||||
import { z } from "zod";
|
||||
import { findUniqueOrThrow } from "../db/helpers.js";
|
||||
import {
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type ResourceDailyAvailabilityContext,
|
||||
} from "../lib/resource-capacity.js";
|
||||
import { fmtEur } from "../lib/format-utils.js";
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc.js";
|
||||
import { createTRPCRouter, planningReadProcedure, requirePermission } from "../trpc.js";
|
||||
|
||||
const DAY_KEYS: (keyof WeekdayAvailability)[] = [
|
||||
"sunday",
|
||||
@@ -860,7 +860,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
/**
|
||||
* Get ranked resource suggestions for a staffing requirement.
|
||||
*/
|
||||
getSuggestions: protectedProcedure
|
||||
getSuggestions: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
requiredSkills: z.array(z.string()),
|
||||
@@ -875,9 +875,12 @@ export const staffingRouter = createTRPCRouter({
|
||||
minProficiency: z.number().min(1).max(5).optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => queryStaffingSuggestions(ctx.db as unknown as StaffingSuggestionsDbClient, input)),
|
||||
.query(async ({ ctx, input }) => {
|
||||
requirePermission(ctx, PermissionKey.VIEW_COSTS);
|
||||
return queryStaffingSuggestions(ctx.db as unknown as StaffingSuggestionsDbClient, input);
|
||||
}),
|
||||
|
||||
getProjectStaffingSuggestions: protectedProcedure
|
||||
getProjectStaffingSuggestions: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string().min(1),
|
||||
@@ -888,6 +891,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
requirePermission(ctx, PermissionKey.VIEW_COSTS);
|
||||
const project = await findUniqueOrThrow(ctx.db.project.findUnique({
|
||||
where: { id: input.projectId },
|
||||
select: {
|
||||
@@ -937,7 +941,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
};
|
||||
}),
|
||||
|
||||
searchCapacity: protectedProcedure
|
||||
searchCapacity: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
startDate: z.coerce.date(),
|
||||
@@ -1064,7 +1068,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
/**
|
||||
* Analyze utilization for a specific resource over a date range.
|
||||
*/
|
||||
analyzeUtilization: protectedProcedure
|
||||
analyzeUtilization: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
resourceId: z.string(),
|
||||
@@ -1179,7 +1183,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
/**
|
||||
* Find capacity windows for a resource.
|
||||
*/
|
||||
findCapacity: protectedProcedure
|
||||
findCapacity: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
resourceId: z.string(),
|
||||
@@ -1307,7 +1311,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
return windows;
|
||||
}),
|
||||
|
||||
findBestProjectResource: protectedProcedure
|
||||
findBestProjectResource: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
@@ -1319,9 +1323,12 @@ export const staffingRouter = createTRPCRouter({
|
||||
roleName: z.string().optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => queryBestProjectResource(ctx.db as unknown as BestProjectResourceDbClient, input)),
|
||||
.query(async ({ ctx, input }) => {
|
||||
requirePermission(ctx, PermissionKey.VIEW_COSTS);
|
||||
return queryBestProjectResource(ctx.db as unknown as BestProjectResourceDbClient, input);
|
||||
}),
|
||||
|
||||
getBestProjectResourceDetail: protectedProcedure
|
||||
getBestProjectResourceDetail: planningReadProcedure
|
||||
.input(
|
||||
z.object({
|
||||
projectId: z.string().min(1),
|
||||
@@ -1335,6 +1342,7 @@ export const staffingRouter = createTRPCRouter({
|
||||
}),
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
requirePermission(ctx, PermissionKey.VIEW_COSTS);
|
||||
const project = await findUniqueOrThrow(ctx.db.project.findUnique({
|
||||
where: { id: input.projectId },
|
||||
select: {
|
||||
|
||||
Reference in New Issue
Block a user