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
@@ -116,7 +116,7 @@ export async function GET(request: Request) {
.join("; ");
await createNotificationsForUsers({
db: prisma as any,
db: prisma,
userIds: adminUsers.map((u) => u.id),
type: "SYSTEM_ALERT",
title: `Auth Anomaly Detected (${report.anomalies.length} signal${report.anomalies.length > 1 ? "s" : ""})`,
@@ -23,8 +23,7 @@ export async function GET(request: Request) {
if (deny) return deny;
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const alertsSent = await checkChargeabilityAlerts(prisma as any);
const alertsSent = await checkChargeabilityAlerts(prisma);
return NextResponse.json({
ok: true,
@@ -32,10 +31,10 @@ export async function GET(request: Request) {
checkedAt: new Date().toISOString(),
});
} catch (error) {
logger.error({ error, route: "/api/cron/chargeability-alerts" }, "Chargeability alert cron failed");
return NextResponse.json(
{ ok: false, error: "Internal error" },
{ status: 500 },
logger.error(
{ error, route: "/api/cron/chargeability-alerts" },
"Chargeability alert cron failed",
);
return NextResponse.json({ ok: false, error: "Internal error" }, { status: 500 });
}
}
@@ -25,8 +25,7 @@ export async function GET(request: Request) {
if (deny) return deny;
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const reminderCount = await checkPendingEstimateReminders(prisma as any);
const reminderCount = await checkPendingEstimateReminders(prisma);
return NextResponse.json({
ok: true,
@@ -35,9 +34,6 @@ export async function GET(request: Request) {
});
} catch (error) {
logger.error({ error, route: "/api/cron/estimate-reminders" }, "Estimate reminder cron failed");
return NextResponse.json(
{ ok: false, error: "Internal error" },
{ status: 500 },
);
return NextResponse.json({ ok: false, error: "Internal error" }, { status: 500 });
}
}
@@ -90,7 +90,7 @@ export async function GET(request: Request) {
if (adminUsers.length > 0) {
await createNotificationsForUsers({
db: prisma as any,
db: prisma,
userIds: adminUsers.map((u) => u.id),
type: "SYSTEM_ALERT",
title: "CRITICAL: Health Check Failed",
@@ -128,7 +128,7 @@ export async function GET(request: Request) {
.join(", ");
await createNotificationsForUsers({
db: prisma as any,
db: prisma,
userIds: adminUsers.map((u) => u.id),
type: "SYSTEM_ALERT",
title: `Security Audit: ${highSeverity.length} high-severity finding(s)`,
@@ -22,8 +22,7 @@ export async function GET(request: Request) {
if (deny) return deny;
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await sendWeeklyDigest(prisma as any);
const result = await sendWeeklyDigest(prisma);
return NextResponse.json({
ok: true,
@@ -32,9 +31,6 @@ export async function GET(request: Request) {
});
} catch (error) {
logger.error({ error, route: "/api/cron/weekly-digest" }, "Weekly digest cron failed");
return NextResponse.json(
{ ok: false, error: "Internal error" },
{ status: 500 },
);
return NextResponse.json({ ok: false, error: "Internal error" }, { status: 500 });
}
}