Files
HealthLog/src/lib/query-keys/admin.ts
T
Marc-André Bombeck d7e616eaa8 feat(ai): add operator-shared central Codex connection with per-user opt-in
Introduce an operator-level ChatGPT-subscription (Codex) credential that the
operator connects once and shares server-wide, plus a per-user switch to route
AI egress through it.

- Schema (migration 0235): three encrypted columns on AppSettings for the
  operator's central Codex access/refresh tokens and the ChatGPT-Account-ID
  claim, plus expiry/connected-at/status; a per-user useCentralCodex flag
  (default false). Register the new encrypted columns in the rotation registry
  and script.
- Resolution: add the admin-codex chain type; append it to a user's resolved
  chain only when they opted in AND the operator connected it. Tokens refresh
  server-side against the singleton row (CAS-style), same primitives as the
  per-user Codex path.
- Budget: bill an admin-codex primary against the operator cost cap, not the
  user plan — it drains the operator's account.
- Consent: admin-codex is server-managed external egress, gated by the existing
  consent machinery (self-snapshot and document surfaces alike). No existing
  consent path is weakened.
- Document order: rank admin-codex with the subscription tier (last), so the
  document class stays local-first.
- UI: admin device-code connect/disconnect card (cookie-only admin routes) with
  honest copy on account pooling, shared rate limits, and training-by-default;
  a per-user opt-in switch shown only once the operator has connected it, off by
  default, behind a one-time honesty confirm.
- i18n across all six locales; unit tests for the chain type, budget cap,
  consent gate, vision capability, and document order; a mocked e2e for both
  the admin connect surface and the per-user switch.

The central credential's tokens are encrypted at rest and never returned to a
non-admin API; the opt-in only takes effect once the operator has connected the
shared account.
2026-07-10 00:10:56 +02:00

84 lines
3.4 KiB
TypeScript

/**
* Query keys — admin surfaces (users, tokens, logs, backups, feedback,
* audit log, host metrics, invites).
* Part of the centralized factory; aggregated in `./index.ts`.
*/
export const adminKeys = {
/**
* v1.4.41 — admin surfaces. Pre-fix every admin section declared its
* own bare-literal `["admin", "<name>"]`. Routing through the factory
* lets a single rename change every consumer in lockstep.
*/
adminAiQuality: () => ["admin", "ai-quality"] as const,
/**
* v1.16.6 — operator-wide AI key (the `admin-openai` chain fallback).
* Read/write via `/api/admin/ai-settings`; the user-facing
* `insightsSettings.hasAdminKey` flag mirrors the configured state.
*/
adminAiServerKey: () => ["admin", "ai-server-key"] as const,
/**
* Operator-shared central Codex (ChatGPT subscription) connection status.
* Read/write via `/api/admin/central-codex`; the user-facing
* `insightsSettings.centralCodexAvailable` flag mirrors the connected state.
*/
adminCentralCodex: () => ["admin", "central-codex"] as const,
adminAppLogs: (
traceId: string | undefined,
action: string | undefined,
level: string | undefined,
range: string | undefined,
) => ["admin", "app-logs", traceId, action, level, range] as const,
adminAssistantFlags: () => ["admin", "settings", "assistant-flags"] as const,
/** v1.18.0 — operator-level server-wide module availability matrix. */
adminModuleAvailability: () =>
["admin", "settings", "module-availability"] as const,
adminBackups: () => ["admin", "backups"] as const,
/** v1.23 — encryption coverage + rotation progress (admin Encryption section). */
adminEncryptionStatus: () => ["admin", "encryption", "status"] as const,
adminCoachFeedback: () => ["admin", "coach-feedback"] as const,
adminFeedback: (status: string) => ["admin", "feedback", status] as const,
adminFeedbackRoot: () => ["admin", "feedback"] as const,
adminHostMetrics: (window: string) =>
["admin", "host-metrics", window] as const,
/** v1.15.20 — registration invite list (admin Users section). */
adminInvites: () => ["admin", "invites"] as const,
adminAuditActions: () => ["admin", "audit-log", "actions"] as const,
adminAuditOverview: () => ["admin", "audit-log", "overview-preview"] as const,
/**
* v1.4.42 W3-QUERYKEY-LONGTAIL — paginated + filtered audit-log
* read used by the login-overview admin section. The `filtered`
* discriminator at index 2 keeps the no-arg `adminAuditLog(filter)`
* cache slot byte-distinct so its consumers don't collide.
*/
adminAuditLogFiltered: (params: {
filter: string;
page: number;
perPage: number;
actor: string;
actionFilter: string;
target: string;
range: string;
}) =>
[
"admin",
"audit-log",
"filtered",
params.filter,
params.page,
params.perPage,
params.actor,
params.actionFilter,
params.target,
params.range,
] as const,
adminSettings: () => ["admin", "settings"] as const,
adminStatus: () => ["admin", "status"] as const,
/** v1.17.1 — operator-wide notification delivery-health panel. */
adminNotificationHealth: (hours: number) =>
["admin", "notification-health", hours] as const,
adminUsers: () => ["admin", "users"] as const,
adminTokens: () => ["admin", "tokens"] as const,
adminAuditLog: (filter: unknown) => ["admin", "audit-log", filter] as const,
};