KeyLM Project Documentation
KeyLM is a hybrid free-tier and BYOK multi-provider chat app built with Next.js App Router, Prisma, and Postgres. This page documents the product flow, backend APIs, and data model in one place.
Overview
A single workspace where users can start on a shared Groq free pool, then move to their own OpenAI, Gemini, or Anthropic keys.
Hybrid Access
Signed-in users can choose shared Groq Free or Xiaomi MiMo Pro models before or alongside personal keys.
Model Catalog
Models are normalized across providers and cached for 24 hours per user.
Streaming Chat
Server-sent events deliver token deltas with stop and retry safety.
Threaded History
Threads persist provider, model, settings, message history, and token usage.
Quick Start
1. Install dependencies
npm install2. Create the environment file
cp .env.example .env
# set DATABASE_URL, APP_AUTH_SECRET, APP_ENCRYPTION_KEY, NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, GROQ_API_KEY, MIMO_API_KEY3. Generate an encryption key
node -e "console.log(Buffer.from(require('crypto').randomBytes(32)).toString('base64'))"4. Run database migrations
npm run prisma:migrate5. Start the dev server
npm run devEnvironment
Required variables for local development and production.
- DATABASE_URL
- Postgres connection string used by Prisma.
- APP_AUTH_SECRET
- HMAC secret for signing session tokens.
- NEXT_PUBLIC_SUPABASE_URL
- Supabase project URL used for passwordless Email Auth.
- NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
- Supabase publishable/anon key used to request Magic Links and verify OTP codes.
- NEXT_PUBLIC_TURNSTILE_SITE_KEY
- Cloudflare Turnstile public site key rendered on the passwordless login/register form.
- APP_PUBLIC_BASE_URL
- Public app origin used to build the /auth/callback Magic Link redirect URL.
- APP_ENCRYPTION_KEY
- 32-byte base64 key for encrypting provider secrets.
- GROQ_API_KEY
- Server-only API key used for the four shared KeyLM Free Groq models.
- GROQ_BASE_URL
- Groq base URL, defaults to https://api.groq.com/openai/v1.
- GROQ_FREE_MODEL
- Initial shared Groq model selection and demo model, defaults to moonshotai/kimi-k2-instruct-0905.
- GROQ_FREE_FALLBACK_MODELS
- Optional comma-separated Groq fallback models if the primary free model is unavailable.
- MIMO_API_KEY
- Server-only Xiaomi MiMo API key used for the shared Pro models.
- MIMO_BASE_URL
- Xiaomi MiMo base URL, defaults to https://api.xiaomimimo.com/v1.
- FREE_USER_DAILY_LIMIT
- Per-user daily shared-catalog request limit, defaults to 50.
- FREE_GLOBAL_DAILY_LIMIT
- Global daily shared-catalog request limit, defaults to 100.
- RATE_LIMIT_PER_MINUTE
- Optional request limit for chat and password reset endpoints.
- PASSWORD_RESET_TTL_MINUTES
- Legacy password reset TTL. Passwordless OTP/link expiry is configured in Supabase Auth as 900 seconds.
Supabase setup: enable Email Auth, add http://localhost:3000/auth/callback and your production callback URL to Auth redirect URLs, set Email OTP expiry to 900 seconds, enable Captcha with Cloudflare Turnstile, add TURNSTILE_SECRET_KEY only in Supabase Dashboard, and include both the Magic Link and OTP token in the Supabase email template if you want users to choose either method.
User Flow
- Create an account or sign in.
- Choose a KeyLM Free Groq model or Pro Xiaomi MiMo model while daily quota is available.
- Add a provider key and validate it with a lightweight request when you want BYOK mode.
- Load the model list for connected providers and create BYOK threads.
- Send a message and stream responses via SSE.
- Persist assistant output, token usage, and continue the thread.
Architecture
The app is split into route handlers under src/app/api and reusable services undersrc/lib.
Auth and sessions
Supabase passwordless email auth with Magic Links/OTP and signed, httpOnly app session cookies.
Key management
Provider keys are stored encrypted, masked in UI, and audited.
Provider adapters
OpenAI, Gemini, Anthropic, Groq, and Xiaomi MiMo adapters normalize models, streaming, and usage.
Model service
Model lists are cached per key and refreshed on demand.
Thread service
Threads and messages are persisted with idempotent request IDs.
Shared-catalog quotas
Per-user and global daily counters gate all shared Groq Free and Xiaomi MiMo Pro requests.
Project Structure
src/app
App Router pages and API route handlers.
src/lib
Core services, providers, crypto, auth, and utilities.
prisma
Database schema and migrations.
src/app/globals.css
Shared theme and component styles.
API Endpoints
Auth
/api/auth/register
Send a Supabase passwordless signup Magic Link or OTP.
/api/auth/login
Send a Supabase passwordless login Magic Link or OTP.
/api/auth/verify-otp
Verify an email OTP and start the app session.
/auth/callback
Handle Magic Link callback, sync the user, and start the app session.
/api/auth/logout
Clear the session cookie.
/api/auth/me
Return the current session user.
/api/auth/password-reset/request
Legacy password reset endpoint; passwordless auth does not require it.
/api/auth/password-reset/confirm
Legacy password reset confirmation endpoint.
Provider keys
/api/providers/:provider/keys
Validate and store a new key.
/api/providers/:provider/keys
List keys for a provider.
/api/providers/:provider/keys/:keyId/validate
Re-validate a stored key.
/api/providers/:provider/keys/:keyId
Revoke a key.
Models
/api/providers/:provider/models
Return cached models, with optional refresh=true.
/api/providers/:provider/models/refresh
Force a model refresh and update cache.
Free usage
/api/usage/free
Return the current shared-catalog model list and user/global quota snapshot.
Threads and messages
/api/threads
Create a BYOK or shared KeyLM Free/Pro thread.
/api/threads
List threads for the user.
/api/threads/:threadId
Get a thread and its messages.
/api/threads/:threadId
Delete a thread.
/api/threads/:threadId/messages
Send a message, stream SSE deltas, and persist token usage.
Data Model
User
id, email, passwordHash?, supabaseUserId, lastLoginAt, createdAt
ProviderKey
provider, keyCiphertext, keyMask, status, lastValidatedAt, lastUsedAt
ProviderModelCache
provider, keyId, models, fetchedAt, expiresAt
Thread
provider, model, systemPrompt, settings, status, updatedAt
Message
threadId, role, content, providerMessageId, clientRequestId, metadata.usage
AuditLog
action, provider, keyId, metadata, createdAt
PasswordResetToken
tokenHash, expiresAt, usedAt
UserDailyFreeUsage
userId, day, count
GlobalDailyFreeUsage
day, count
UX Behavior
- All signed-in users can choose the shared KeyLM Free/Pro catalog while quota remains.
- The shared catalog and BYOK model controls remain available independently.
- Model lists are cached for 24 hours and can be refreshed manually.
- Threads are locked to the provider and model chosen at creation, including shared Groq and Xiaomi MiMo threads.
- After 5 shared requests, the UI shows a reminder that personal keys use a separate provider account.
- Streaming responses show deltas in real time with stop support.
- Each assistant reply shows prompt, output, and total token usage when available.
Security
- Provider keys are encrypted at rest and never returned in plaintext.
- The shared Groq and Xiaomi MiMo keys stay server-side and are never exposed to clients.
- Supabase verifies Magic Links/OTPs; the app then issues its existing signed httpOnly session cookie.
- Rate limiting protects chat streaming and password reset requests.
- Audit logs track key lifecycle events for traceability.
- Model and thread access is scoped to the authenticated user.
Edge Cases
- A key that was valid can be revoked later; validation endpoints update status.
- If a model refresh fails, cached models are served with a stale flag.
- Duplicate message requests are deduped via clientRequestId.
- Shared-catalog quota resets at 00:00 UTC for both the user bucket and the global pool.
- Rate limits return retryable errors with 429 responses.
Testing
- Unit: provider adapters, crypto helpers, and validation schemas.
- Integration: provider routing, quota reservation, model caching, and thread persistence.
- E2E: use KeyLM Free and Pro models, exhaust, quota, connect a key, stream chat, and save history.
- Security: verify secrets never leak to logs or responses.
Roadmap
- Tool calling and structured output support.
- Vision attachments with capability gating.
- Usage analytics and per-model cost reporting.
- Team workspaces with shared key vaults.