BYOK Anthropic and Gemini keys stored encrypted alongside Case.dev gateway
kveton added a second credential surface to the CaseMark fork. Users can now route Anthropic and Gemini calls directly with their own keys instead of going through the Case.dev model gateway. The credential management sits in a new `provider_api_credentials` Postgres table with encrypted storage, live validation, and soft-delete on removal.
The bulk of the work lands in backend/src/lib/providerCredentials.ts (385 lines). Keys are encrypted with encryptCaseApiKey/decryptCaseApiKey - the same AES-256-GCM path used for Case credentials - and validated on save by calling the provider's /v1/models endpoint. The stored row tracks last4, verified_at, last_checked_at, capabilities: { llm, model_count }, and status (verified/unverified/invalid). Migration 009_provider_credentials.sql creates the table; the review pass (2032ca81) added revoked_at and changed key removal from a hard delete to a soft-delete update that zeroes the key material.
A MIKE_ALLOW_SERVER_PROVIDER_KEY_FALLBACK env var lets non-production environments fall back to keys in .env. The initial commit defaulted this to true, which the review pass corrected: production now unconditionally returns false regardless of the env var.
On the frontend side, provider availability logic was consolidated into modelAvailability.ts. Four components (ChatInput, TRChatPanel, TabularReviewView, useSelectedModel) had each been computing this independently; the refactor gives them a shared providerCredentialState() function. The Account > Models page was reorganized into Case.dev, Model Providers, Model Defaults, and Storage sections.
The /case-models endpoint picks up a provider_errors field in its response when a live model catalog call fails, logging a fallback to the static model list with a generic "Provider model catalog unavailable; using static fallback" message rather than forwarding the raw error detail to clients.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?