Stripe webhooks
Run the app locally, then forward Stripe events:Redis rate limiter QA
Redis client 6 uses RESP3 and requires Node.js 20 or newer. Use a disposable local Redis instance for the opt-in TCP tests; never point them at customer storage. SetOVERLAY_REDIS_URL explicitly and run
NODE_OPTIONS=--require=./scripts/ci/register-server-only.cjs npx tsx --test src/server/shared/providers/redis-rate-limiter.test.ts.
The live cases verify shared limits, concurrent requests and expiry; the same
file retains ordinary unit tests for fail-closed behavior without Redis.
Auth
WorkOS sign-in flows require the local callback URL to match the WorkOS application settings. Keep local, Preview, and Production WorkOS credentials separate. For OIDC deployments, including Keycloak-compatible realm issuers, verify browser callback wiring and token claims before production use. Default web sign-in/sign-up and server SSO callbacks use the shared authenticated home (/app/work) when no return destination is supplied. Explicit same-origin paths, including /account, and supported desktop handoff redirects retain their existing validation and routing.
Protected-route sign-in redirects preserve the full path and query for both missing and invalid sessions, including Better Auth sign-in. In particular, /account?desktop_code_challenge=... must retain its PKCE challenge through sign-in and the account-settings alias; do not reduce the return destination to a pathname. Protected APIs still return 401 JSON rather than browser redirects.
PR preview authentication
Migration previews usehttps://pr-<number>.preview.getoverlay.io with the
registered WorkOS sandbox wildcard callback. They do not require the paid
Vercel preview suffix. POST /api/auth/preview-login accepts the
x-overlay-preview-secret header only when both deployment markers say preview,
the canonical origin is valid, and the WorkOS client is Overlay’s sandbox.
The server authenticates its configured QA email/password, checks the returned
user ID against the seeded identity, and creates the normal encrypted session.
It never returns provider tokens. Missing or incorrect configuration returns
404 before provider access; authenticated requests are rate limited.
Keep PREVIEW_LOGIN_SECRET, PREVIEW_LOGIN_PASSWORD, and the sandbox API key
in the web app’s Preview scope. Convex receives only the seed user ID/email and
the matching internal secrets. The existing browser Convex-token endpoint issues
the short-lived subscription token after this login.
Storage
R2 and S3-compatible storage flows use server-mediated upload and download routes. Test:- Presign URL creation.
- Upload completion.
- Owner-scoped content access.
- File deletion.
Observability
PostHog and Sentry are optional locally. Use separate projects or DSNs per environment. Do not send local secrets, access tokens, or customer data in logs.Composio
Composio catalog and connection setup requireCOMPOSIO_API_KEY on the Next.js server. Hosted deployments resolve WorkOS Vault first and fall back to the server environment. Keep the Vault object and deployment variable aligned when rotating the key.
Verify configuration through GET /api/v1/integrations?action=health. Catalog requests fail with an actionable provider/configuration error when the key is missing, rejected, or the upstream catalog is unavailable; an empty catalog is reserved for a successful response with no matches.
Connector visibility is workspace-scoped through workspaceConnectors. On the first Personal-workspace read after upgrading, active Composio accounts with no mapping in any workspace are assigned to Personal. Existing workspace mappings are never moved or duplicated.
MCP tools
The MCP OAuth adapter preserves the SDK’s authorization-serverissuer binding
on both client information and tokens, inside the existing encrypted JSON
credential fields. Credentials loaded without an issuer are withheld from the
SDK and require reconnecting; do not infer their issuer from a new discovery
response or silently stamp existing secrets. The SDK refuses to send bound
credentials to a different issuer. This upgrade needs no new Convex schema
field.
AI SDK toolsContext is keyed by executable tool name. call_mcp_tool receives
its user, conversation, turn, and model attribution under the
call_mcp_tool key; a flat context object fails validation before the MCP
network call and leaves the transcript looking stuck. MCP calls have a
30-second default timeout and record a terminal execution row for success or
failure.
Slack import via Composio
Slack import uses Composio’sSLACKBOT toolkit with direct tool execution — not the LLM session-based flow used by agent tools. This is a deterministic, paginated backfill that runs as a server-side background job.
Architecture
Key files
Direct tool execution vs LLM sessions
Agent tools usecreateBrowserUnifiedTools() which creates a Composio session per user and lets the LLM choose tool calls. The Slack importer does not use sessions. Instead it calls Composio’s REST API directly:
data field (sometimes as a JSON string that must be parsed).
Composio Slackbot auth config
TheSLACKBOT toolkit requires a Composio-managed auth config before OAuth can work. If one doesn’t exist, the connect flow will fail. Auth configs are created via:
connectResponse({ providerKey: 'slackbot' }) flow works from the UI.
Rate limit considerations
- The backfill worker adds small delays between thread fetches (200ms) to avoid rate limits.
- Composio may return rate limit errors from Slack’s API. The worker logs these but continues with other channels.
- Channel listing is cached per import job — the worker lists channels once at the start.
- For large workspaces, the import may take several minutes. Progress is reported via Convex job status updates after each channel.
Slack access limitations
A Slack bot/user token only sees conversations the authenticated account can access:- Public channels: broadly accessible
- Private channels: only if the bot/user is a member
- DMs: only the authenticated user’s DMs
- MPIMs: only if the user is a participant