Skip to content

feat(subapp): CORS for Vercel sub-apps + ElevenLabs TTS proxy#29

Merged
dougdevitre merged 1 commit intomainfrom
feat/subapp-ai-tts-proxy
Apr 18, 2026
Merged

feat(subapp): CORS for Vercel sub-apps + ElevenLabs TTS proxy#29
dougdevitre merged 1 commit intomainfrom
feat/subapp-ai-tts-proxy

Conversation

@dougdevitre
Copy link
Copy Markdown
Owner

Summary

Enables the 49 cotrackpro-* Vercel sub-apps to use this server as a shared AI/TTS proxy, so provider API keys stay server-side instead of being inlined into browser bundles.

  • CORS: extends the sub-app allow-list to match cotrackpro-*.vercel.app (including Vercel's team-suffixed preview URLs), in addition to the existing *.cotrackpro.com and localhost origins. Lookalike domains and non-cotrackpro- Vercel tenants stay rejected.
  • TTS proxy: new POST /api/ai/tts — Clerk JWT required, per-user rate-limited, calls ElevenLabs REST (text-to-speech/{voiceId}) and streams the mp3 back to the caller. Voice ID, output format, and per-request char cap are all configurable via env.
  • Sub-app model override: new ANTHROPIC_SUBAPP_MODEL env (defaults to claude-opus-4-7) for /api/ai/complete, so the voice pipeline keeps its Sonnet default independently.
  • Env vars added: ANTHROPIC_SUBAPP_MODEL, ELEVENLABS_TTS_VOICE_ID, ELEVENLABS_TTS_OUTPUT_FORMAT, TTS_MAX_CHARS_PER_REQUEST, TTS_RATE_LIMIT_PER_MIN, TTS_RATE_LIMIT_PER_HOUR.

This is infrastructure only — no sub-app is migrated yet. A follow-up PR will pilot the swap in cotrackpro-story before rolling out to the rest.

Test plan

  • npm run typecheck clean
  • Full test suite passes (312/312) including 12 new CORS tests and 14 new TTS tests
  • Set new env vars in the Vercel project (see .env.example additions)
  • After deploy, hit POST /api/ai/tts from a sub-app origin with a valid Clerk session → expect audio/mpeg bytes
  • Verify CORS preflight from https://cotrackpro-story.vercel.app returns the origin echo + Access-Control-Allow-Credentials: true
  • Verify preflight from a non-cotrackpro *.vercel.app origin returns no CORS headers (fail-closed)
  • Rate-limit trip: >10 TTS requests/min from one user returns 429 with Retry-After

Follow-ups (not in this PR)

  • Pilot the Gemini → proxy swap in cotrackpro-story
  • Roll out the same swap to the remaining 48 cotrackpro-* apps
  • Action for @dougdevitre after merge: rotate the leaked GEMINI_API_KEY — it's been inlined into production browser bundles across the sub-apps.

🤖 Generated with Claude Code

…S proxy

Adds a server-side TTS proxy so the 49 cotrackpro-* Vercel sub-apps can
synthesize speech without shipping provider keys in the browser bundle.
The proxy authenticates with Clerk, rate-limits per user, and only
accepts origins on *.cotrackpro.com or cotrackpro-*.vercel.app.

Also switches the sub-app AI proxy default model to ANTHROPIC_SUBAPP_MODEL
(claude-opus-4-7) so the voice pipeline keeps its Sonnet default
independently.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@dougdevitre dougdevitre merged commit 8261792 into main Apr 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant