perf(api): eliminate N+1 queries, add query guards and missing indexes

- Notification fan-out: replace sequential for loops with Promise.all (allocation-effects, notification-broadcast, create-notification)
- Public holiday batch: group resources by location combo, resolve holidays once per group, replace per-holiday delete/findFirst/create with 3 batched queries (~18K → ~5 queries)
- Add take guards to unbounded findMany calls (resource-analytics: 5000, resource-marketplace: 2000, resource-capacity: 1000, chargeability-report: 2000)
- auto-staffing: add select with only needed fields + take: 5000
- schema.prisma: add 5 missing indexes (ManagementLevel.groupId, Blueprint.isActive/target, Comment.parentId, Vacation.requestedById, Resource.managementLevelGroupId)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-09 08:35:13 +02:00
parent 1d6d75ecf6
commit 1204c186ef
12 changed files with 213 additions and 104 deletions
+32
View File
@@ -54,6 +54,22 @@ type DbClient = Parameters<typeof listAssignmentBookings>[0] & {
resource: {
findMany: (args: {
where: { isActive: true };
select?: {
id?: true;
displayName?: true;
eid?: true;
skills?: true;
lcrCents?: true;
chargeabilityTarget?: true;
valueScore?: true;
availability?: true;
countryId?: true;
federalState?: true;
metroCityId?: true;
country?: { select: { code: true } };
metroCity?: { select: { name: true } };
};
take?: number;
}) => Promise<Array<{
id: string;
displayName: string;
@@ -155,6 +171,22 @@ export async function generateAutoSuggestions(
// 4. Fetch all active resources and their current bookings
const resources = await db.resource.findMany({
where: { isActive: true },
select: {
id: true,
displayName: true,
eid: true,
skills: true,
lcrCents: true,
chargeabilityTarget: true,
valueScore: true,
availability: true,
countryId: true,
federalState: true,
metroCityId: true,
country: { select: { code: true } },
metroCity: { select: { name: true } },
},
take: 5000,
});
if (resources.length === 0) return;