fix(types): replace structural DB types with Pick<PrismaClient> and remove Prisma boundary as any casts

Replace ~440 lines of hand-written structural DB client types across 7 lib files
with `Pick<PrismaClient, ...>` from @capakraken/db. This eliminates all `as any`
casts at Prisma boundaries (cron routes, allocation effects, vacation procedures)
and surfaces two pre-existing bugs:
- weekly-digest.ts: `db.allocation.count()` called non-existent model (fixed → demandRequirement)
- estimate-reminders.ts: `submittedAt` field doesn't exist on EstimateVersion (fixed → updatedAt)

Also adds root eslint.config.mjs so lint-staged can lint package files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 15:09:16 +02:00
parent 82acc56b8d
commit 9051ff73d0
17 changed files with 257 additions and 581 deletions
+26 -22
View File
@@ -1,12 +1,21 @@
import type { PrismaClient } from "@capakraken/db";
import { createDemandRequirement, fillDemandRequirement } from "@capakraken/application";
import { buildTaskAction, CreateDemandRequirementSchema, FillDemandRequirementSchema } from "@capakraken/shared";
import { z } from "zod";
import type {
CreateDemandRequirementSchema,
FillDemandRequirementSchema,
} from "@capakraken/shared";
import { buildTaskAction } from "@capakraken/shared";
import type { z } from "zod";
import { checkBudgetThresholds } from "../../lib/budget-alerts.js";
import { generateAutoSuggestions } from "../../lib/auto-staffing.js";
import { invalidateDashboardCache } from "../../lib/cache.js";
import { logger } from "../../lib/logger.js";
import { dispatchWebhooks } from "../../lib/webhook-dispatcher.js";
import { emitAllocationCreated, emitAllocationUpdated, emitNotificationCreated } from "../../sse/event-bus.js";
import {
emitAllocationCreated,
emitAllocationUpdated,
emitNotificationCreated,
} from "../../sse/event-bus.js";
export function runAllocationBackgroundEffect(
effectName: string,
@@ -27,44 +36,37 @@ export function invalidateDashboardCacheInBackground(): void {
runAllocationBackgroundEffect("invalidateDashboardCache", () => invalidateDashboardCache());
}
export function checkBudgetThresholdsInBackground(
db: import("@capakraken/db").PrismaClient,
projectId: string,
): void {
export function checkBudgetThresholdsInBackground(db: PrismaClient, projectId: string): void {
runAllocationBackgroundEffect(
"checkBudgetThresholds",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => checkBudgetThresholds(db as any, projectId),
() => checkBudgetThresholds(db, projectId),
{ projectId },
);
}
export function dispatchAllocationWebhookInBackground(
db: import("@capakraken/db").PrismaClient,
db: PrismaClient,
event: string,
payload: Record<string, unknown>,
): void {
runAllocationBackgroundEffect(
"dispatchWebhooks",
() => dispatchWebhooks(db, event, payload),
{ event },
);
runAllocationBackgroundEffect("dispatchWebhooks", () => dispatchWebhooks(db, event, payload), {
event,
});
}
export function generateAutoSuggestionsInBackground(
db: import("@capakraken/db").PrismaClient,
db: PrismaClient,
demandRequirementId: string,
): void {
runAllocationBackgroundEffect(
"generateAutoSuggestions",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
() => generateAutoSuggestions(db as any, demandRequirementId),
() => generateAutoSuggestions(db, demandRequirementId),
{ demandRequirementId },
);
}
export async function createDemandRequirementWithEffects(
db: import("@capakraken/db").PrismaClient,
db: PrismaClient,
input: z.infer<typeof CreateDemandRequirementSchema>,
) {
const demandRequirement = await db.$transaction(async (tx) => {
@@ -132,7 +134,7 @@ export async function createDemandRequirementWithEffects(
}
export async function fillDemandRequirementWithEffects(
db: import("@capakraken/db").PrismaClient,
db: PrismaClient,
input: z.infer<typeof FillDemandRequirementSchema>,
) {
const result = await fillDemandRequirement(db, input);
@@ -151,8 +153,10 @@ export async function fillDemandRequirementWithEffects(
invalidateDashboardCacheInBackground();
checkBudgetThresholdsInBackground(db, result.assignment.projectId);
if (result.updatedDemandRequirement.headcount > 0
&& result.updatedDemandRequirement.status !== "COMPLETED") {
if (
result.updatedDemandRequirement.headcount > 0 &&
result.updatedDemandRequirement.status !== "COMPLETED"
) {
generateAutoSuggestionsInBackground(db, result.updatedDemandRequirement.id);
}