diff --git a/src/lib/ai/capabilities/usage.ts b/src/lib/ai/capabilities/usage.ts index e3eda8f27..decf7e4ff 100644 --- a/src/lib/ai/capabilities/usage.ts +++ b/src/lib/ai/capabilities/usage.ts @@ -17,6 +17,7 @@ * (`PUT /api/auth/me/ai-usage`); a managed profile has no choice of its own * and follows the instance default. */ +import { readOperatorRow } from "@/lib/settings/operator-row"; import { prisma } from "@/lib/db"; import { getEvent } from "@/lib/logging/context"; import { memoizePerRequest } from "@/lib/request-cache"; @@ -83,14 +84,7 @@ export function aiUsageSettingsFromRow( export function loadAiUsageSettings(): Promise { const read = async (): Promise => { try { - const row = await prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: { - aiUsageMaxLevel: true, - aiUsageDefaultLevel: true, - aiSyncRegenGapHours: true, - }, - }); + const row = await readOperatorRow(); return aiUsageSettingsFromRow(row); } catch { getEvent()?.addWarning( diff --git a/src/lib/ai/provider.ts b/src/lib/ai/provider.ts index 9b03bfc5d..9c788bbee 100644 --- a/src/lib/ai/provider.ts +++ b/src/lib/ai/provider.ts @@ -1,4 +1,5 @@ import type { AIProvider, CompletionResult } from "./types"; +import { readOperatorRow } from "@/lib/settings/operator-row"; import { bindResponseTimeout } from "./effective-timeout"; import { bindReasoningEffort } from "./reasoning-effort"; import { prisma } from "@/lib/db"; @@ -1145,16 +1146,6 @@ const PRESENCE_USER_SELECT = { aiResponseTimeoutSeconds: true, } as const; -const PRESENCE_SETTINGS_SELECT = { - adminAiKeyEncrypted: true, - adminAiModel: true, - adminAiBaseUrl: true, - adminCodexConnectionStatus: true, - adminCodexAccessTokenEncrypted: true, - adminCodexRefreshTokenEncrypted: true, - adminCodexAccountIdEncrypted: true, -} as const; - const NO_PRESENCE: ProviderPresence = Object.freeze({ entries: [], localOcrEnabled: false, @@ -1217,10 +1208,7 @@ export function probeProviderChain( where: { id: recordId }, select: PRESENCE_USER_SELECT, }), - prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: PRESENCE_SETTINGS_SELECT, - }), + readOperatorRow(), ]); if (!row) return NO_PRESENCE; const policy = providerCredentialPolicy(authority, row.managedProfileAt); diff --git a/src/lib/ai/reasoning/controls.ts b/src/lib/ai/reasoning/controls.ts index 7b1420c36..a34655774 100644 --- a/src/lib/ai/reasoning/controls.ts +++ b/src/lib/ai/reasoning/controls.ts @@ -5,6 +5,7 @@ * Server-only. The decision itself is the pure `resolveReasoning` in * `./resolve.ts`; this file only gathers its inputs. */ +import { readOperatorRow } from "@/lib/settings/operator-row"; import { prisma } from "@/lib/db"; import { annotate, getEvent } from "@/lib/logging/context"; import { memoizePerRequest } from "@/lib/request-cache"; @@ -70,10 +71,7 @@ function loadMemoisedControls(): Promise { "ai-reasoning-controls", async () => { try { - const row = await prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: { aiReasoningEnabled: true, aiReasoningMaxEffort: true }, - }); + const row = await readOperatorRow(); return { enabled: row?.aiReasoningEnabled ?? true, maxEffort: parseReasoningMaxEffort(row?.aiReasoningMaxEffort), diff --git a/src/lib/auth/mfa-enrollment.ts b/src/lib/auth/mfa-enrollment.ts index 4a78ffd7b..89378c827 100644 --- a/src/lib/auth/mfa-enrollment.ts +++ b/src/lib/auth/mfa-enrollment.ts @@ -16,6 +16,7 @@ * out; the operator/CLI escape hatch (`scripts/disable-mfa.ts`, toggling the * policy off) is the recovery path of last resort. */ +import { readOperatorRow } from "@/lib/settings/operator-row"; import { cookies } from "next/headers"; import { prisma } from "@/lib/db"; import { shouldEmitSecureCookie } from "@/lib/auth/secure-cookie"; @@ -44,10 +45,7 @@ export async function resolveMfaEnrollmentRequired( // Already has a confirmed TOTP secret → enrolled, nothing required. if (user.totpConfirmedAt) return false; - const settings = await prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: { mfaRequired: true }, - }); + const settings = await readOperatorRow(); const policyApplies = Boolean(settings?.mfaRequired) || user.mfaEnforced; if (!policyApplies) return false; diff --git a/src/lib/feature-flags/index.ts b/src/lib/feature-flags/index.ts index 5d1b613bc..e46b5ad0f 100644 --- a/src/lib/feature-flags/index.ts +++ b/src/lib/feature-flags/index.ts @@ -1,4 +1,4 @@ -import { prisma } from "@/lib/db"; +import { readOperatorRow } from "@/lib/settings/operator-row"; import { getEvent } from "@/lib/logging/context"; import { memoizePerRequest } from "@/lib/request-cache"; @@ -57,16 +57,7 @@ export function loadAssistantSwitches(): Promise { "assistant-flags", async () => { try { - const settings = await prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: { - assistantEnabled: true, - assistantCoachEnabled: true, - assistantBriefingEnabled: true, - assistantInsightStatusEnabled: true, - assistantDocumentAiEnabled: true, - }, - }); + const settings = await readOperatorRow(); return resolveAssistantFlags({ enabled: settings?.assistantEnabled ?? true, coach: settings?.assistantCoachEnabled ?? true, diff --git a/src/lib/modules/operator-availability.ts b/src/lib/modules/operator-availability.ts index d90b44a10..42c045c3e 100644 --- a/src/lib/modules/operator-availability.ts +++ b/src/lib/modules/operator-availability.ts @@ -36,7 +36,7 @@ * 0343 folded the blob's `coach` key into the switch and removed it, and a * `coach` key that still turns up in the blob is ignored. */ -import { prisma } from "@/lib/db"; +import { readOperatorRow } from "@/lib/settings/operator-row"; import { getAssistantFlags } from "@/lib/feature-flags"; import { getEvent } from "@/lib/logging/context"; import { memoizePerRequest } from "@/lib/request-cache"; @@ -84,10 +84,7 @@ export function resolveOperatorAvailability( /** The raw availability blob; a read error reads as "nothing disabled". */ async function loadAvailabilityBlob(): Promise { try { - const settings = await prisma.appSettings.findUnique({ - where: { id: "singleton" }, - select: { moduleAvailabilityJson: true }, - }); + const settings = await readOperatorRow(); return settings?.moduleAvailabilityJson ?? null; } catch { getEvent()?.addWarning( diff --git a/src/lib/settings/operator-row.ts b/src/lib/settings/operator-row.ts new file mode 100644 index 000000000..00fd0972d --- /dev/null +++ b/src/lib/settings/operator-row.ts @@ -0,0 +1,56 @@ +/** + * The operator's settings that every app boot reads, in one statement per + * request. + * + * `/api/auth/me` resolved six answers out of the `AppSettings` singleton (the + * MFA policy, the Assistant switches, the module availability, the provider + * presence, the AI usage bounds and the reasoning controls), each with its own + * `SELECT` of a few columns, so one client boot read the same row six times. + * Each reader now takes its columns from this one read, memoised for the + * request (and read afresh for every call inside a background job, whose one + * event spans a whole multi-user pass, like the readers it serves). + * + * A reader keeps its own error handling: a failed read rejects here, and the + * memo forgets a rejected read so the next caller tries again. + */ +import type { Prisma } from "@/generated/prisma/client"; +import { prisma } from "@/lib/db"; +import { memoizePerRequest } from "@/lib/request-cache"; + +export const OPERATOR_ROW_SELECT = { + mfaRequired: true, + assistantEnabled: true, + assistantCoachEnabled: true, + assistantBriefingEnabled: true, + assistantInsightStatusEnabled: true, + assistantDocumentAiEnabled: true, + moduleAvailabilityJson: true, + adminAiKeyEncrypted: true, + adminAiModel: true, + adminAiBaseUrl: true, + adminCodexConnectionStatus: true, + adminCodexAccessTokenEncrypted: true, + adminCodexRefreshTokenEncrypted: true, + adminCodexAccountIdEncrypted: true, + aiUsageMaxLevel: true, + aiUsageDefaultLevel: true, + aiSyncRegenGapHours: true, + aiReasoningEnabled: true, + aiReasoningMaxEffort: true, +} as const satisfies Prisma.AppSettingsSelect; + +export type OperatorRow = Prisma.AppSettingsGetPayload<{ + select: typeof OPERATOR_ROW_SELECT; +}>; + +export function readOperatorRow(): Promise { + return memoizePerRequest( + "operator-settings-row", + () => + prisma.appSettings.findUnique({ + where: { id: "singleton" }, + select: OPERATOR_ROW_SELECT, + }), + { freshInBackground: true }, + ); +}