Skip to main content

Stripe webhooks

Run the app locally, then forward Stripe events:
Use matching Stripe test secrets for that explicitly selected personal development Convex backend. Do not forward to customer production; each isolated PR preview has its own test endpoint. The former Next.js webhook route was removed.

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. Set OVERLAY_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 use https://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 require COMPOSIO_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-server issuer 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’s SLACKBOT 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 use createBrowserUnifiedTools() 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:
This gives deterministic pagination, retries, checkpointing, and predictable costs. The response wraps Slack’s API response in a data field (sometimes as a JSON string that must be parsed).

Composio Slackbot auth config

The SLACKBOT 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:
The auth config is project-scoped in Composio. Once created, the standard 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
The coverage report distinguishes public/private/DM/MPIM counts so users understand what was actually imported vs what exists in their Slack workspace. For full workspace export, Slack’s admin ZIP export or Enterprise Discovery API would be needed (not implemented yet).